[squeak-dev] Re: talk on Newspeak online

Vassili Bykov smalltalkbigot at gmail.com
Fri May 9 16:49:07 UTC 2008


On Thu, May 8, 2008 at 4:50 PM, Igor Stasenko <siguctua at gmail.com> wrote:
> In given example i assumed that ExternalInterface is basic abstract
> class, which provides common interface,
> while different subclasses providing specialization for each separate platform.

Good point. I thought to gloss over this to keep my explanation
shorter but no such luck. :) However, this leads to interesting
follow-up examples.

In your original example, and usually in real cases like this in
Smalltalk, the superclass plays several roles. As a class it captures
the common behavior, sometimes abstract sometimes not. As an object,
it is a factory. As a name in the developer's vocabulary it references
a piece of functionality, or a "module".

In my example an instance of the outer class is really a factory and a
module. I omitted a superclass for capturing common behavior. A more
complete example with more descriptive names would be:

class ExternalInterfaceFactory platform: platform = (
    | platformName = platform platformName. |
) (
    private class ExternalInterface = (...)

    private class MacOSExternalInterface = ExternalInterface (...)

    ...and so on...
)

Now that the pieces are more appropriately named, hopefully it is
clearer how they relate. You create an instance of a factory by
sending #platform: to the outer class, and then you create instances
of the nested classes by sending #new to the factory.

Note that the outer class still combines two roles: a module providing
some functionality and a factory. If need be, they can also be
separated:

class ExternalInterfaceModule platform: platform = (
|
    platformName = platform platformName.
    factory = InterfaceFactory new.
|
) (
    private class InterfaceFactory = ( | | ) (
        new = (
            platformName = 'MacOS' ifTrue: [^MacOSExternalInterface new].
            ...
        )
    )

    private class ExternalInterface = (...)

    private class MacOSExternalInterface = ExternalInterface (...)

    ...and so on...
)

This would now be used in a two-step process, first creating the
module and then retrieving its factory to create instances. A factory
could be designed to support "plugins" for other platforms registered
with a message such as #createInstancesFor:using:. Presumably some or
all of the nested classes would be public in such a scenario to make
them available for subclassing.  A user module might look something
like:

class MyApp platform: platform externalInterface: moduleClass = (
|
    ExternalInterfaceModule = moduleClass platform: platform.
    ExternalInterface = ExternalInterfaceModule factory.
    AbstractExternalInterface = ExternalInterfaceModule ExternalInterface.
|
    Interface createInstancesFor: 'Foobar' using: [^FoobarExternalInterface new]
) (
    private class FoobarExternalInterface  = AbstractExternalInterface (...)
    ...
)

This also illustrates how a class declared under one name can be bound
to a different name within another module, to avoid a name conflict or
on a whim. Here we suppose that in our code we want to write
"ExternalInterface new" to create instances of interfaces, so we bind
that name to a factory. To avoid a conflict, the ExternalInterface
class retrieved from the module is made known as
AbstractExternalInterface.

Regarding prototypes--this isn't a model Newspeak supports *as part of
the language standard*. But before you say "boo!"--neither does
Smalltalk. A particular Smalltalk *system* may allow making a behavior
an instance of itself as an implementation-specific feature.
Smalltalk-80 had no facilities for that. Adrian Kuhn first implemented
his Protalk on VisualWorks last year, but a year or so before he
wouldn't be able to. Eliot had a thought to try self-instantiating
behaviors for a personal project he and I worked on in 2006, and that
was when he fixed the VM to allow that.

All this is to say that I'm being very careful to draw a line between
what a language provides as a standard facility which doesn't cross a
metalevel boundary, and reflective capabilities of certain
implementations. With this caveat--of course, a particular Newspeak
implementation and *in a particular context*--more on this after the
example--could support creation of self-instantiated behaviors. Of
course, it would be done through a controllable mirror interface. For
example:

   newBehavior: Behavior new.
   newMirror: (ObjectReflection reflect: newBehavior).
   newMirror
      objectClass: newBehavior;
      methodAt: #foo put: ...

Unlike the usual model of just changing the class, here the reflection
facility is in control of what reflective capabilities the code
receives in the form of a mirror.  For example, an untrusted
application in a web browser might receive a mirror with no
modification capabilities, or no capabilities at all. Find and watch
Gilad's talk at Google on "objects as software services", it will give
you an idea of what are the priorities for Newspeak.

Cheers,

--Vassili



More information about the Squeak-dev mailing list