Squik language features

Anthony Hannan ajh18 at cornell.edu
Mon Apr 14 07:10:40 UTC 2003


Hello fellow Squeakers,

Below is a set of language features that I would like to see in a new
language evolved from Squeak.  I call it Squik.  Many of these ideas
have been discussed on this list before in one form or another,
including private instance variables recently.  But I think as a whole
this set of features makes for a nice modular and flexible language.  I
plan on making this my next project, so I am very interested in getting
your input first.  I know there are related projects: Class boxes,
Traits, and Exupery compiler.  Maybe we should collaborate.

Cheers,
Anthony

The text below can also be found on
http://minnow.cc.gatech.edu/squeak/Squik.

Squik: A proposal for a next generation Smalltalk

Startup

A Squik image file, like a Squeak image file, holds a heap of objects.
The first object is a ImageHeader object whose first field points to a
suspended context. The Squik boot program just loads a named squik image
file into memory and resumes its suspended context.

No VM

The boot program is not a VM; there is no VM. Any machine code needed is
implemented in library modules (dlls) that are loaded as objects when
needed. For example, Interpreter is an object that responds to messages
by calling the named function in its library module. These library
messages replace primitive syntax.

Interpreter is really the only object that requires machine code
implementation. All other traditional VM behavior like the garbage
collector can be implemented in the image. Raw pointer manipulation must
be added to the bytecode set, but only privleged classes will have
access to them (Low-Level Operations are described later).

No Instance Variables

There are no instance variables. Instance fields can only be accessed
via #instVarAt: and #instVarAt:put:. Of course, accessor methods may be
implemented for convenience.

No Global or Pool Variables

There are no global or pool variables, only class variables. A global
such as Array would be a class variable of ProtoObject, accessible to
all subclass methods. Class variables can not be assigned to directly,
they must be set using classVarAt:put:.

Implicit Temporary Variable Declaration

Temps are the only variables we can directly assign to. This allows us
to interpret the first assignment to a temporary as its declaration as
well. This eliminates the need for the temp var declaration list.

Factories

In Squeak, metaclasses serve both as behaviors and factories. In Squik,
factories are separate from their instance behavior. Class variables
reference other class factories, not the classes themselves. "Class"
methods are implemented on the factories, which are arranged in a
hierarchy that mirrors their corresponding classes. So, "Object" returns
a factory. "Object new" returns an instance. "Object instanceClass"
return the class of Object instances. And "Object class" returns its
class, ObjectFactory, a subclass of Factory and an instance of Class.
There are no more metaclasses.

Namespaces and Bound Selectors

A class can only send messages of other class interfaces that are
visible to it. An interface of a class is the set of its selectors that
are new to the class and not inherited from any superclass. An interface
is visible to a class iff the class has the interface's factory in one
of its class variables or inherited class variables. For example, a
class A can send the message #do: to an object only if A has or inherits
a class variable that contains the Collection factory. For messages sent
to self, interfaces of its own class hierarchy are also visible.

Selectors are more than just symbols. A Selector points back to the
interface that it is a part of. The compiler binds message sends to the
selector found in a visible interface. If more than one interface
contains the same selector name than the compiler pops up the choice to
the programmer. The programmer usually knows which interface he is
targeting. The interface chosen is prefixed to the message, such as
"block blockClosure.value".

Multiple Inheritance

To support polymorphism of bound selectors, mulitple inheritance has to
be allowed. For example, if a subclass of Foo wants to simulate block
behavior it will have to inherit from BlockClosure as well. Message
conflicts are avoided since prefixes must be used in ambiguous
situations. Also, since there are no instance variables, subclasses can
reimplement accessors as it sees fit.

If inst var fields are inherited from mulitple branches then some fields
must be repositioned in the subclass. The compiler will automatically
override super methods that access fields directly (instVarAt:(put:))
with copies containing the correct field positions in the subclass.

Using Namespaces for Privacy

As stated before a class can only send messages of interfaces visible to
it. To hide "private" methods from other classes, you can put them in a
new subclass that is not visible to outside classes. The new subclass
would only be visible to the original factory object so it can create
instances of it. For example, SetPriv could be a new subclass of Set.
Only SetFactory, the class of the Set factory, would hold SetPriv in a
class variable so it can create instances of it in response to "Set
new".

Low-Level Operations

The compiler translates messages sent to RawOp to special bytecodes that
directly manipulate data (no message sends). For example, to read the
header word of an object A, you would write "header := RawOp longAt: A".
header would contain raw data which should never be the receiver of a
message. It should only be used in arguments to other RawOp messages.

The RawOp object and interface would only be visible to the garbage
collector and other low level classes.



More information about the Squeak-dev mailing list