Repository navigation
Tags: lispnik/objc
Tags
Release 0.4.1 -- examples and documentation src/ is byte for byte what it was at v0.4.0. Anyone depending on #:objc gets nothing new, which is what the patch number says; this exists so a distribution has a fixed point to reference rather than a moving master. OBJC-BLOCK-LIVE-P gains the example it was missing, in audio.lisp -- the only example whose block outlives the form that made it, because a render block is held by an engine that will call it until stopped. That is the case WITH-OBJC-BLOCK cannot serve and the reason MAKE-OBJC-BLOCK is exported. With it, every exported symbol that should have an example has one; the three that remain are type descriptors that appear in signatures the runtime hands you and never in code you write. doc/demo.md scripts the live-coding demo over canvas.lisp and shader.lisp, with every form in it run before it was written down -- which changed it three times. The pitch was "edit in Emacs and watch the window change", and that cannot work: AppKit needs thread 1, SLY evaluates on a worker, and the entry points refuse. It is a terminal beside a window, which is the better demo anyway. 934 checks, green on arm64 and Intel.
Release 0.4.0 -- six examples, and two tests that were not testing an… …ything src/ changes here are comments and docstrings only: no behaviour, no exported symbol. Anyone depending on #:objc gets nothing new. The minor number is for the size of everything else, not for an API change -- block creation, which is the last real addition, shipped in 0.3.0. SIX NEW EXAMPLES, chosen by measuring which exported operators no example used and closing the gap: collections.lisp -- a Lisp object as a first-class citizen of Cocoa's own data structures, asked -hash, -isEqual: and -description and answering from CLOS slots. The CLOS half of the library had no example at all. browser.lisp -- a class browser over the library's own introspection, which was exported, documented, and called by nothing but the test suite. undo.lisp -- NSUndoManager running Lisp methods as its undo operations, and the discovery that a forwarding proxy is invisible here: -prepareWithInvocationTarget: cannot be sent to, because dispatch resolves the Method first. True of every -forwardInvocation: proxy. memory.lisp -- retain counts and pools, with deaths observed through OBJC-OBJECT-DESTROYED rather than inferred. A tagged pointer's retain count is nonsense and inconsistent nonsense: 2^64-1 from a short NSString, 2^63-1 from a tagged NSNumber. Draining a pool on the wrong thread is a memory fault, not a diagnostic. A missing pool is silent even under OBJC_DEBUG_MISSING_POOLS. notifications.lisp -- NSNotificationCenter, where the handler runs on the thread that POSTED rather than the one that registered. A dead observer is no longer a crash: modern macOS zeroes the reference, which the folklore has not caught up with. geometry, strings, task and plugin -- the four that finish the job. COCOA is now fully exercised and so is every defining macro. A filled foreign structure passes anywhere its vector does; NSNotFound is NSIntegerMax and not -1; an NSString counts UTF-16 code units so a Lisp SUBSEQ at a Cocoa offset is in bounds and wrong; -waitUntilExit before draining a pipe deadlocks past 64KB; and a typedef is erased at the boundary. TWO TESTS WERE PASSING WITHOUT TESTING ANYTHING. ASDF:SYSTEM-RELATIVE-PATHNAME quotes a wildcard, so "src/*.lisp" named a file that does not exist and DIRECTORY returned NIL. ONLY-ABI-LISP-KNOWS-ABOUT-SB-ALIEN -- the test CLAUDE.md describes as what keeps the seam a seam -- was green with sb-alien: sitting in src/cocoa.lisp. Both file-scanning tests now enumerate properly and assert a floor on the count first, and each was verified by breaking something on purpose. An audit found no test in the suite that makes zero assertions: 266 tests, 266 ran, 931 checks. Green on arm64 and Intel.
Release 0.3.1 -- four more examples, and no library change at all src/ is byte for byte what it was at v0.3.0. Anyone depending on #:objc gets nothing new, which is what the patch number is saying; everything here is in examples/ and test/. metal.lisp -- GPU compute. A Metal Shading Language kernel compiled at run time from a string and run over a Lisp vector, so the GPU program is data another function wrote. It exercises more of the bridge at once than anything else: a plain C entry point, message sends, an owned-object convention, and MTLSize passed by value. Its timing report corrects the claim people expect -- for element-wise work the GPU LOSES, because copying dominates, and it wins by 200x or more only once the arithmetic per element covers two copies. scene-kit.lisp -- a scene graph built from Lisp forms and rendered to a PNG with no window, because SCNRenderer draws into an image rather than a view. Ships no assets; the picture is described where you can read it. audio.lisp -- an AVAudioSourceNode whose render block is a Lisp closure, so the block is the instrument. Tested offline through the engine's manual rendering mode, which is deterministic and silent and needs no sound hardware, and demonstrated live through PLAY, which no test calls. The header records what makes it unlike everything else here: the render block runs on a real-time thread with a deadline, where a collection that overruns is audible. shader.lisp -- one MSL expression per pixel, written to a PNG or animated in a window through the canvas's draw hook. The canvas's live loop with the GPU drawing. Four traps recorded, each found by writing the example rather than by reasoning about it: MTLCreateSystemDefaultDevice signals FLOATING-POINT-OVERFLOW. The bridge masks Cocoa's traps around message sends, and a CFFI:DEFCFUN is not a message send. -bitmapData returns `unsigned char *', which encodes exactly as a C string does, so plain INVOKE hands back "" -- the buffer starts with a zero byte. INVOKE-INTO with :POINTER is what the manual provides, and nothing else here had needed it. -dispatchThreads: rounds the grid up to whole threadgroups, so a kernel without a bounds check writes past its buffer on any size that is not a multiple of the group. An amplitude of 0.5 comes back peaking at 0.5/sqrt(2), because the main mixer attenuates. Measured; the pan-law explanation is inference and is labelled as such. 820 checks, green on stock and safepoint builds, both architectures.
Release 0.3.0 -- Objective-C blocks The headline is block creation. This library could pass and receive a block as an opaque pointer but not make one, which put the completion-handler half of macOS out of reach. MAKE-OBJC-BLOCK builds a real Block ABI literal whose invoke function is an alien callable, so Cocoa calls a Lisp closure; CALL-OBJC-BLOCK goes the other way. Structures cross by value in both directions. Foundation now sorts an NSArray through a Lisp comparator, and dispatch_async enters Lisp on a libdispatch worker thread. Lifetimes are refcounted through the descriptor's copy and dispose helpers, so freeing a block Cocoa still holds is safe: the copy took its own reference. WITH-OBJC-BLOCK is right even for asynchronous work. This widens the OBJC package past the 42 symbols the LispWorks manual documents, by 8. LispWorks has no block interface in OBJC at all -- it lives in the FLI there, and there is no FLI here. The seam test asserts the exact exported set rather than a count, so the widening had to be written down rather than absorbed. Two bugs fixed, both silent, both older than this release: Every BOOL ARGUMENT was NO. :bool mapped to sb-alien's (boolean 8), which converts on SBCL's side and wants a generalized boolean, while every conversion function here produces the integer 1 or 0 -- and (boolean 8) given 1 arrives as NO. Results were right the whole time, which is why the suite never noticed. It is (unsigned 8) now. INVOKE returned a pointer into a freed buffer for a structure result with no Lisp representation. It read as plausible numbers. It signals now, and names INVOKE-INTO. Both were found by writing examples, not by writing tests. A concurrency limit, measured and then lifted. Two libdispatch worker threads inside Lisp at once kill a stock SBCL: a GC stops the world by signalling, and Darwin will not signal a workqueue thread at all -- you get one for free only because the collector skips the thread that triggered it. Building SBCL --with-sb-safepoint removes it entirely, and CI now proves that on every push. PARALLEL-MAP exists and refuses, rather than crashing, where the build cannot take it. Ten new examples: GCD, NSURLSession, NaturalLanguage, Core Image, a dispatch-source file watcher, KVO, NSDataDetector, NSPredicate and variadic sends, headless PDFKit, Quick Look thumbnails, and NSWorkspace. Several exist to record a trap rather than to show an API. 798 checks, green on stock and safepoint builds, on both architectures.
objc v0.2.0 A live drawing canvas (examples/canvas.lisp): a real NSView subclass whose -drawRect: calls a Lisp function you redefine at the REPL while the window is open, drawing with NSColor and NSBezierPath. It puts struct-by-value on the hot path -- -drawRect: takes an NSRect by value, every shape passes NSRect/NSPoint by value -- and renders offscreen for a windowless test. Underneath, large structure returns are routed through objc_msgSend_stret where the ABI calls for it. CI: dropped the vanished free Intel runner, then took the Intel label that still exists. And the Status section now says plainly there will be no FLI compatibility layer.
objc 0.1.0 The LispWorks Objective-C interface, reimplemented for SBCL on macOS. All 42 symbols of the OBJC package and all 11 of COCOA, with the LispWorks names and lambda lists. Dynamic dispatch through compiled per-signature trampolines over objc_msgSend; Objective-C classes defined from Lisp with real IMPs, taking and returning C structs by value. 643 checks, green locally and on CI. Behaviour the manual leaves ambiguous was settled against a running LispWorks Personal 8.1 and is asserted against. Known limits: an Objective-C exception terminates the process, variadic methods need :variadic-num-of-fixed, and arm64 is the only architecture this has run on.