David and Harold discuss a new programming language and environment they have been researching which allows to contextual, multidimensional dispatch of messages so that the behaviour of objects depends on the context of the method invocation. They also give a quick demonstration of a development environment they have build to explore these ideas in Self.
Named after the majestic, awe inspiring Anas platyrhynchos, the latest Self release 4.5.0 is now available for download.
What’s new since 4.4?
- Build system redone by Tobias Pape. Now based on cmake, with a single modern build process for both Linux and OS X. The VM can be built on both GCC and Clang on the latest vesions of both operating systems.
- New Self Control.app on OS X to manage your running worlds as a more robust and featured replacement for the older ‘Self Droplet’. Use of this app is optional and you can still access the Self VM through the command line.
- New look for standard world, with better fonts, colours and greater use of space.
- Various fixes to the standard world, including a new build script ‘worldBuilder.self’ replacing several ad hoc build scripts.
- Updated Self Handbook at handbook.selflanguage.org
Sources for the VM and for the basic Self world are available as always from the GitHub repository. Although Self, like Smalltalk80, can use an image (in Self called a snapshot of a world), this can be built from text sources.
Self Mallard is available for OS X and Linux. You can download binaries:
- For OSX, a disk image containing the Self Control.app and a prebuilt clean snapshot (“Clean.snap”). Copy the app to your Applications folder, run it and click the Choose snapshot… button.
- For Linux, a gripped tar file containing a prebuilt 32-bit binary and Clean.snap. Unpack, then run ./Self -s Clean.snap
Following on from his SelfVM build for Android x86, Chris Double has fixed up some bitrot in an old Self application, which allows sharing a Self world through a Java applet (without requiring a X11 server).
Check out his writeup here, including a screencast of how to make it work. His changes have been merged into the Self tree.
Chris Double has announced a build of the Self VM for x86 Android. No GUI yet and only x86:
This follows on from my previous post on an error handling mechanism. Prompted by David Ungar to think further on how that mechanism could be made more general and powerful, and less of a one off special exception, this is a description of one way in which certain objects can adjust their behaviour based not only on their delegatees and but also on a ‘perspective’ – a viewpoint bound to a process. It’s a great example I think of the power of Self as a language.
Subjectivity and Us
Normal objects in Self are objective – that is their behaviour depends only on themselves and will be the same in all contexts.
In 1996, Randall B Smith and David Ungar wrote a paper called “A simple and unifying approach to subjective objects” (download as a pdf) in which they described a system called ‘Us’ where objects were subjective rather than objective. The behaviour of Us objects (in technical terms the lookup mechanism for delegation) depended on what perspective the message was sent with.
Objects were to be built up in two planes – by normal delegation and by layering pieces onto the whole. Each message received by the object would be dispatched into that three dimensional space based upon not only message selector but also on an implicit argument to the message – the perspective object.
So two people could look at an object in two different ways – to me it might be a circle, to you a set of slots. Or it might look like a pie chart to me and a table to you. An object would be not so much a concrete thing like a pebble but a ‘figment of its viewers beliefs’ (as the authors quote Alan Kay as saying)
Randall and David didn’t build a complete system this way. I don’t know of anyone who has, although the work done on Classboxes in Smalltalk-80 and Java is a very interesting application of similar ideas to modularisation and there are a number of other interesting papers which cite the Us paper.
I understand Randall and David’s paper correctly, a pure Us implementation would require a check at every lookup, so turning Self into Us would take a lot of effort and changing the VM lookup code if it were to be efficient.
However it might be a useful exercise to build a mechanism to investigate and play with subjectivity, even if that mechanism doesn’t get us all the benefits of a full-blown Us.
This is a thought experiment on some of the Us principles. It’s not an implementation of Us and neither Randall not David should be blamed for its inadequacies! In particular, perspectives in Us are not necessarily bound to a process, nor do they necessarily as I understand it hold true beyond the initial method – that is unlike the mechanism below a perspective wouldn’t stay fixed for the call stack until the original method exits. As well, Us wasn’t envisioned as an being a capacity of Self but as a new language which was a superset of the existing Self language.
On the other hand, as you’ll see below, this is a short and simple experiment!
The mechanism I have in mind looks like this:
To make an object “subjective”, we share the subjective mixin:
o: (| m* = mixins subjective |)
Ordinary slots will behave ordinarily:
o: (| m* = mixins subjective. x = 1. |). o x == 1
To create subjective behaviour, we add layers (with overlapping slots) as parent slots:
o: (| m* = mixins subjective. default* = (| hello = ('Hello') |). french* = (| hello = ('Bonjour') |) |)
These layers shouldn’t themselves have further parent slots, and they should overlap so that their slots are the same. If we want undefined behaviour we need to do something like
(| hello = (|l = lobby| l raiseError) |) rather than leaving the hello slot out of our layer.
Once we have done this, sending our object the message ‘hello’ will get us the string ‘Hello’. However, if we do:
[o hello] @ 'french'
then we will get the result ‘Bonjour’.
Perspective objects must understand a message
forObject: o Selector: s, where o is the current self of the object doing the lookup and s is the selector. They return a canonicalString. Strings know to return themselves, so ‘french’ is a shortcut for a perspective object which always returns ‘french’. The system finds the perspective object by sending a message to self, so
[o hello] @ french
will, as you would expect, look for the perspective object by sending the message ‘french’ to self.
Perspectives are placed on the process. They are not placed in a stack; but the @ message on traits block manages reinstalling the old perspective after itself, so if we have:
([o hello] @ 'french'), ' ', o hello
the result is ‘Bonjour Hello’
OK, so how is this done?
(1) We create the mixin:
mixins subjective = (| ambiguousSelector: sel Type: t Delegatee: d MethodHolder: m Arguments: a = ( | l = lobby | sel sendTo: self DelegatingTo: ((l process this perspective forObject: self Selector: sel) sendTo: self) WithArguments: a ) |)
This traps the vm send error message
ambiguousSelector:Type:Delegatee:MethodHolder:Arguments: and chooses which of the parents of our object is resent the message based on sending to the perspective object found on
process this the message
forObject:Selector:, which returns a string which is then sent to our original object to get the appropriate delagatee.
globals process is given a new assignable slot called ‘perspective’ with the contents the string ‘
traits block is given a new slot @
@ p = ( | h. r | h: process this perspective. process this perspective: p. r: onNonLocalReturn: [|:v| process this perspective: h. v ] IfFail: [|:e| process this perspective: h. raiseError ]. process this perspective: h. r )
which handles installing a new perspective and cleaning up after itself, and
traits string is given a new slot
forObject: o Selector: s = (self)
so that we can just use a string if we find it easier.
What can we do with it?
Well, first off let’s implement the error handling style mechanism from last post.
defaultBehavior = "Apart from all the other slots of course" (| m* = mixins subjective. default* = (| error: x = ( "Normal existing error code") |). logErrors* = (| error: x = ( "Some code to log our error but not bring up debugger") |). logErrorsPerspective = 'logErrors' |)
Now we’re done. If we try to get
9 / 0
we get a debugger, whereas if we do
[ 9 / 0 ] @ logErrorsPerspective
then any error silently logged without a debugger being opened.
This isn’t perfect, and there are I’m sure lots of interestingly dangerous corner cases and unexpected behaviours lurking, but its a great example of way in which a simple but well thought out base like Self gives us great power. There are many languages where this wouldn’t nearly be as nice to play with.
This is at least in part because no one has written one – Self certainly is flexible to accommodate a Smalltalk style exceptions system. But it is also a matter of choice. Instead of exceptions, Self encourages the pattern of passing an exception handling block to methods that need it, so an
openResource method could become
openResourceIfFail: [|:e| doSomthingElse: e ]
Changing this would be a reasonably serious task. Exception systems are tricky things, which can cause confusion. They introduce complexity, and I’m not convinced (at least at the moment) that their benefits outweigh the added complexity. (If you want to convince me, a good way would be to write a nice idiomatic Self exception handling framework :) )
But this certainly doesn’t mean that we can’t improve how Self handles exceptional circumstances.
One area of annoyance with the current setup is the
error: message. Very similar to the old Smalltalk-80 mechanism, sending
error: to most objects results in the process in question being suspending, and a debugger opened in the morphic desktop or on the command line interface.
9 / 0 or doing
error: 'Error' to see what I mean.
This is necessary. Despite good intentions, there will always be situations where things break. But sometimes this isn’t the error handling behaviour that we want. For example, in a testing framework we want errors in our tests to be logged, not immediately debugged.
How to improve this? I’ve uploaded to Github a patch under an experimental
error-handling branch. You can read the diff online. In summary what it does is:
defaultBehaviorimplements two important methods regarding errors.
The first is the method
handleError: error, which takes as its argument an error object. Prototypes for different error objects are found in
The second is the more usually called
error: errorStringmethod, which takes a string description of the error and creates an error object and calls
handleError:in turn calls the errorHandler code on its process object which sends the error object to the currently selected error handler, which could be a block or an object understanding
Some default error handling objects can be found in the
errorHandlersglobal. They include the
defaulthandler (which opens a debugger), the
silentSuspendhandler which silently suspends the process, the
silentAborthandler which aborts the process and the
returnNilhandler which always returns nil.
A handler can be installed by calling
process this errorHandler: myNewHandler, but this is not recommended.
Instead, you should call
[ myCode ] onError: myNewHandlerwhich installs the handler, runs the block and then cleans up after itself by reinstalling the original handler.
As well, there is a global called
raiseError, which is the equivalent to
[|:e| error: e ]and can be used in similar circumstances:
something ifTrue: raiseError
This is *not* an exception system, despite its surface similarity. It does not deal with the stack or dispatch errors differently based on error type. It is not intended to be used for anything except situations where you need to change from the default behaviour of opening a debugger. The encouraged way of handling exceptional circumstances continues to be to pass an exception handler to the method which may require it. On the plus side, it is clean, simple and doesn’t require a lot of explaining.
What do you think about this approach?
The Self handbook, which contains most of the documentation for the Self project, has been available for a while at http://docs.selflanguage.org in html for online reading.
Now I’ve managed to build a PDF version, which can be downloaded for offline reading. It’s 150 pages long and contains a lot of useful information to ponder and inwardly digest.
It’s built though Sphinx and LaTeX. I looked around for alternatives to LaTeX, because I find it a pain (especially when dealing with large tables) and was fascinated to see that (despite the obvious problems with it) there isn’t a clear replacement . Oh well.
Self’s Morphic interface actually has a lot of charm, but unfortunatly it is in a early NeXT fashion. Lots of grey. Or is that gray? One of the things which scratches an itch for me is cleaning up the interface to make it more comfortable to use.
Adventurous people can download a snapshot which shows the current thinking. Not much has changed, but font styles and sizes have been altered and some colour brought in:
The guiding principles for this makeover, which come from the idea of Self itself, is the creative intersection between minimalism and humanism.
More will be coming – why not join us for the ride?
One of the strengths of Self is the number of great published papers that were written by the Self team at Stanford and later at Sun.
We’ve been trying to collect all of these on the Self website on our published papers page – you should really check them out.
Recently John Maloney sent me a paper of his and Randy Smith’s on Morphic from 1995, which I’ve added to the list. It’s called “Directness and liveness in the Morphic user interface construction environment” and its worth reading for the philosophy and structure behind Morphic, Self’s main user interface and its later incarnations in Squeak/Pharo and Dan Ingall’s Lively Kernel.
It has been decreed that it is high time Self joined the Great League of Important Programming Languages (TM) and organised its own IRC channel on Freenode!
Anyway, if you have any Self questions then pop on by Freenode channel #self-lang and visit us.
We promise to be friendly, if not necessarily coherent.