One of the great things about SmalltalkAgents compared to most other similar environments was its great integration with the Macintosh System Software. It accomplished this by creating a great foreign-function interface that let you call arbitrary non-Smalltalk code from within SmalltalkAgents easily, efficiently, and in a way that Just Worked when it came to interacting with the operating system. And the fact that it could do this with the 68000-based Macintosh was a pretty interesting feat, due to the multiplicity of runtime models and calling conventions that wouldn't be unified until the release of the Power Mac.
Here's how it worked: SmalltalkAgents extended normal Smalltalk syntax with an additional construct, the ExternalMethod invocation which was effectively a function call with inline type information wrapped in «double angle brackets». (On a Mac, those are option-\ and option-shift-\ respectively; you could also use << and >> if you wanted.) Not only that, but SmalltalkAgents also supported a concept of structured storage for objects that would allow you to pass around C-style structures and pointers to them very easily.
So an invocation of a foreign function would look like this:
sayHello
| result |
result := «printf(('Hello, world!' asCString):Ptr):Int».
[result < 0] ifTrue: [ Exception raise: 'Error calling printf.' ].
^self
This is a method, sayHello, that invokes the ExternalMethod listed in the module-global ExternalMethodDictionary under the key symbol #printf. It declares the argument and return value types and uses some of the object coercions built into the SmalltalkAgents frameworks to get values that will be passed to the foreign code properly.Creating a new ExternalMethod is very easy, too, especially if you can rely on it to follow one of a couple standard calling conventions. SmalltalkAgents defines all of the basic machine-style parameter types you'd expect, and you pass them at the call site rather than when creating an ExternalMethod, so you don't have to do all sorts of complicated header file parsing that many other similar technologies require you to use. Instead, you can just create what amounts to a list of the external methods you want to support and provide some way to hook them to their actual code (whether via a load of a code resource or a pointer in an external library), and then you can Just Use Them in your Smalltalk code.
It worked great, and I think it's something a lot of modern systems could learn from.