Self for Squeak

pavel_krivanek pavel_krivanek at
Fri Sep 2 23:21:49 UTC 2005

> Pavel,
>> you may be interested in my experimental project named Marvin.
> Yes, I did find it very interesting indeed. I hope you don't mind me
> sending a copy of this to the Self list so that other people who might
> be interested can learn about your project. Perhaps it would be a good
> idea to announce it in the Squeak list too.

There are several reasons why I didn't announce this project in
1) I want to make some minor modifications in the bytecodes generator etc.
2) I still have no VM for Linux. My attempts to build and compile VM
for this platform failed.
3) I wish to introduce it with very simple outliner. We cannot fully
demonstrate the power of this solution without this stuff.
4) I have to translate the most important parts of documentation to

>> It's an attempt to create a Self dialect in Squeak which is
compiled directly to the native bytecodes of Squeak and uses some
little extensions of virtual machine like delegation support etc.
> There were other projects that added a bytecode or two to support this
> kind of thing. It would be nice if this could be done in a fully
> compatible way so that all future VMs could support it even for people
> not interested in using it. The original "blue book" instruction set had
> a few spare opcodes but I would have to check to see if Squeak didn't
> use them all.

My solution adds no next bytecodes to VM specification. Now I only add
two primitives (definition of prototype class) and I modify the
sending and resending mechanism. If the receiver is instance of the
prototype class, VM uses another lookup algorithm based on delegation.

>> You are experienced Self programmer (unlike me) and you may see
some problematic aspects of my concept of Squeak and Self integration
which I haven't perceived. Your comments are welcome.
> It looks great. I only didn't understand why you had to use a non local
> return in the ifTrue:ifFalse: definition in your examples.

Marvin uses the Smalltalk's conventions for methods and blocks. So
Methods return receiver if there's no explicit return command. Methods
in Self return result of the last expression.

> The use of [...] to explicitly control compile-time evaluation is a very
> good idea and something I had borrowed from Forth for a language I
> desiged a while ago. Agora has something similar.

In fact, the main reason why I use square brackets is unambiguous
grammar. The visual separation is important too, in particular if a
programmer uses something like slot = self and then he is surprised
why it contains lobby. However it makes the resultant code less readable.

> Earlier versions of Self were more similar to Marvin in some aspects.
> They had characters as different objects from strings, for example. And
> the slot lookup was closer to your depth first strategy. There were no
> annotations either.

I have never fully understand why Self uses so complicated lookup
mechanism. It prevents some ambiguities but Self then cannot work well
with redefinitions and it's slower. DFS also encapsulates the object
more rigorously because an object is then enclosed entity even for
lookup mechanism.

> I am not sure why you feel you need to add primitives in future versions
> since you seem to have full access to Squeak. While I find the Self
> syntax for primitives much nicer than the old Smalltalk one it seems a
> little odd that while they look exactly like message sends they are
> really subroutine calls since they ignore the receiver type. Something a
> little less global would be nicer.

You're right, Marvin doesn't need primitives. Standard Squeak
primitives and methods of prototype class can play this role as well.

Here's another (runable) expample. It's very simple implementation of

        application = [(|

            globals* = [(|
                privateGlobals* = [(|
                    lobby <- [ nil ] |)] |)].   

            traits = [(|
                privateTraits* = [()] |)].

            kernel <- [ nil ].

            initialize: aKernel = ( 
                kernel: aKernel.
                globals privateGlobals lobby: self.
                    loadModule: #morphicModule 
                    lobby: lobby
                    user: #root).

            main = (
                | m |
                m: morph copy. 
                m color: traits color red.
                m openInHand )


        kernel = [(|
            loadModule: moduleName lobby: root user: user = (
                | module |
                (user == #root )
                    ifTrue: [
                        module: (modules at: moduleName).
                        root globals AddParentSlot: module globalsName
value: module globals veryDeepCopy.
                        root traits AddParentSlot: module traitsName
value: module traits veryDeepCopy.]
                    ifFalse: [ error: 'Unknown user, you cannot load
this module' ]).
            modules = [ 
                Dictionary newFrom: (Array with:
                    #morphicModule -> ( |
                        globalsName = [ #morphicGlobals ].
                        globals* = [(|
                            "" only for demonstration
                            morph = [ Morph new ].      
                            color = [ Color white ] |)].
                        traitsName = [ #traitsGlobals ].
                        traits = [(|
                            "" only for demonstration
                            morph = [ Morph ].
                            color = [ Color ] |)] | ) ) ]

application initialize: kernel.
application main.

-- Pavel

More information about the Self-interest mailing list