Squik language features

Jesse Welton jwelton at pacific.mps.ohio-state.edu
Tue Apr 15 22:17:39 UTC 2003


Anthony Hannan wrote:
> 
> 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).

This strikes me as a misuse of terminology.  If the bytecode set is
not an instruction set for a virtual machine, what is it?  (The
architecture itself seems fine to me, but the terminology could use
clarification.  You shouldn't call a thing not-that-which-it-is.)

> 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.

Again, you don't really not have instance variables; you've just
removed their labels.  This seems like a bad idea to me.  Even if you
remove direct (bytecoded) access to them, you'll still want their
names available for introspection, such as in the debugger.

> No Global or Pool Variables

Having scoped environments in place of global and pool dictionaries
seems like a good generalization, but I'm skeptical about tying this
rigidly to the class heirarchy.  One shouldn't need to change the
inheritance structure of a class in order to specify what package
facilities are available to it.  These are independent concepts.

> Implicit Temporary Variable Declaration

What about lexically nested contexts?  You need a way to determine the
scope of each temp var.

> Factories

It's not clear to me why this should be considered an improvement over
metaclasses.  You've just taken two objects which need to be
maintained in parallel heriarchies (Object, Object class) and replaced
them with three (Object, ObjectFactory, Object instanceClass).  This
seems especially odd given the association you propose between a
factory and the interface defined by its instanceClass, below:

> 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.

How is this applied to messages sent to the factories themselves
(OrderedCollection new)?

> 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".

This may be a good way to handle selector collisions between
protocols.  But it may not: it's verbose, and could produce alot of
false positives.  Consider the implementation of Dictionary, which
uses both BlockClosures and Associations.  Even though there's no
internal conflict in interpreting #value sent to either a block or an
association, Dictionary code would have to specify which protocol
applied in each case, simply because it has access to both.  (That is,
unless you also propose to add static type checking.)

To what interface does a method like #asString belong?  If to Object,
you're losing much of the encapsulation you're working for.  If to
String, you've got an unworkable problem with interface through
inheritance.

> 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.

This seems like another overuse of inheritance to me.  In order for
MyBlockClosureReplacement to *simulate* a BlockClosure, it has to
inherit the implementation (and state!) of BlockClosure?  That sounds
annoying to work around.  It seems to me a noninherited interface
definition can provide namespaces for bound selectors without the
added complexity of multiple inheritance, can work better with helper
methods like asString, and can be more flexible in assisting security
(as for example by providing restricted subsets of interfaces).  Using
inheritance for all scoping severely limits your options.

-Jesse



More information about the Squeak-dev mailing list