Complexity and starting over on the JVM (ideas)

Paul D. Fernhout pdfernhout at kurtz-fernhout.com
Sun Feb 10 22:09:26 UTC 2008


Paul D. Fernhout wrote:
> """
> class Wire {
>   private var sigVal = false
>   private var actions: List[Action] = List()
>   def getSignal = sigVal
>   def setSignal(s: Boolean) =
>     if (s != sigVal) {
>       sigVal = s
>       actions.foreach(action => action())
>     }
>   def addAction(a: Action) {
>     actions = a :: actions; a()
>   }
> }
> """"

In rereading this, I see how this is probably a totally unclear example,
without having spent at least fifteen minutes reading about Scala. :-)
One important issue is that Scala infers types in the body of functions, but
you have to specify the types for function arguments.

A class overview from the book:
"The Wire Class. A wire needs to support three basic actions.
     getSignal: Boolean returns the current signal on the wire.
     setSignal(sig: Boolean) sets the wire’s signal to sig.
     addAction(p: Action) attaches the specified procedure p to the actions
of the wire. All attached action procedures will be executed every time the
signal of a wire changes."

So, imagine some hypothetical original source for this Wire class in Squeak:

    Object subclass: #Wire
	   instanceVariableNames:'sigVal actions'
	   classVariableNames:''
	   poolDictionaries:''
	   category:'Demos'

    init
        sigVal := false.
	"%Translator annotateListType: 'Action'"
        actions := OrderdCollection new.

    getSignal
	^ sigVal.

    addAction: aAction
        actions addFirst: aAction.
        aAction value.

    setSignal: aBoolean
        (aBoolean ~= sigVal) ifTrue: [
           sigVal = aBoolean
           actions do: [:action | action value].
        ].

Line by line here is what is there (and what isn't there compared to C or
Java) to see how Scala could be a useful output medium for translating
Squeak code to an alternative statically typed language instead of C or Java.

> class Wire {

We're defining a class "Wire".

> "private var sigVal = false"

The compiler infers the Boolean type for the instance variable "sigVal" from
the constant assignment. So no need to annotate the Smalltalk code yourself.
Let's ignore the "private" flag.

>   private var actions: List[Action] = List()

This would probably require an annotation saying the List is specialized to
only hold "Action" instances somewhere in the Squeak code for the expected
class of the items of the list.

Notice the list never needs to be deallocated anywhere (unlike, say, a
typical C++ object).

>   def getSignal = sigVal

This is equivalent to a simple accessor method to return the instance var
"sigVal"

>   def setSignal(s: Boolean) =
>     if (s != sigVal) {
>       sigVal = s
>       actions.foreach(action => action())
>     }

This defines a method "setSignal:" where the argument type would have to be
annotated as a "Boolean". Or perhaps the compiler would take a type from the
argument name if it was "aBoolean" or "s_Boolean" if underscores were
allowed. :-) The code iterates over all the previously stored action objects
(notice no types are declared for the temporary variable "action") and each
action (block) is called as a function with no arguments.

>   def addAction(a: Action) {
>     actions = a :: actions; a()

This is how the actions get added. The part after the semicolon is calling
the action and could be on a separate line. Notice the actions don't need to
be deallocated.

Anyway, I haven't tried compiling that, but that's a rough Smalltalk
equivalence. Hopefully one can see how easy that mapping might be (in
theory). The system in this case would also have to know to map "do:" to
"forEach:" and OrderedCollection to List, "addFirst:" to an assignment, and
"value" to a function call. So still some magic going on, including
resolving these from the Smalltalk classes used (perhaps by profiling and
annotating the Smalltalk code as it runs? :-) But possibly there is a lot
less than for C or even Java, to get a lot more. Also, I'll admit I'm a
little fuzzy on how to specify that an "Action" is always a no argument
BlockContext instance (Scala: "type Action = () => Unit"). Probably another
type annotation somewhere, perhaps in a class comment? So, admittedly still
quite a bit of handwaving here. :-) But remember, I am really on,y wanting
to solve the easy cases -- the 1% or even 5% of the code which is a
bottleneck to performance, and I hope that just a little magic with types
and annotations and assumptions and perhaps profiling might be enough to do
that. It's the 80/20 rule. With Scala, I think we could have 80% of the
benefit of high performance with only 20% of the pain and clutter of types
in the specific code. :-) Of course, I'd hope more for 90/10. :-)

Anyway, I'm not suggesting this would not take some work. But I am
suggesting the payoff for such an approach might be high for a small amount
of work. :-) Essentially you would not be as restricted to just Slang operators:
  http://wiki.squeak.org/squeak/2267
(or your own functions built.on those) when running on the JVM and wanting
to remove bottlenecks; you would have the full power of a general OO and
functional programming language to boost Smalltalk performance when needed.
Squeakers on the JVM could then make the same sales pitch Pythoneers do --
code it in one language, and add a little harder to maintain stuff in
another. I know people can do that now with Squeak and C, but Java is simply
*much* easier to maintain across platforms than C for the average programmer
(one reason Jython is becoming a better value proposition than CPython in
some parts of various enterprise systems).

You would still have to code carefully and make some annotations, but you
could (in theory) use a larger set of OO and functional abstractions and
expect Scala to handle them. And the good news is, since Scala is statically
typed, you'd know at once if you were missing an annotation since Scala
would complain about not being able to infer a type. Maybe eventually one
could even report that error back into the Squeak GUI and have the browser
highlight the problematical part of the translation (though with statically
typed systems its not always obvious where the problem is introduced,
especially the fancier the generated Scala code. :-).

The Scala team is small and the language is still evolving. Java is a large
language and getting it changed to help with a Squeak on the JVM would be
difficult. So, if there was some aspect of this translation process which
could benefit from some minor addition to Scala which could generally
supported any dynamically typed language work with Scala better, it might be
conceivable the core language might change to accommodate Squeak's
translation needs. I'm thinking mainly here the way in which Scala would get
called from the JVM by Smalltalk (converting dynamic -> static) and the way
Smalltalk woudl get called through the JVM by Scala (converting static ->
dynamic).

I'd also suggest that, like Smalltalk/X does for C/C++, one could even just
drop Scala code into a browser method, but I'm worried that might seem too
revolting to too many Squeakers. :-) But it would be fairly easy to do for
Scala, Java, or any other JVM language as long as the languages could easily
interoperate semantically (that is, the use Java objects and have some
mutually agreeable way to coordinate their threading. :-) I would somehow
expect Scala code might make more sense to embed at a module level than a
method level though (since it is idiomatically oriented more towards lots of
small interacting functions than, say, one big procedure's worth of Java or C).

That suggests one way to get started, following perhaps in the footsteps of
Smalltalk/X? Code a Smalltalk-ish class browser in, say, Java or Scala or
Jython, and then just start adding Smalltalk stuff bit by bit, versioned in
some repository somewhere (I have a Jython version of an RDF-like system
(Pointrel) I wrote, but any flat file or database could do). A VM with
objects will be running from the start, since the JVM defines it. Then over
time, more and more of the system and tools will be in Smalltalk, as bit by
bit pieces are copied from Squeak (or likely also GNU Smalltalk or any other
free system, respecting the licenses).

The big difference here from a conventional Smalltalk bootstrapping is that
a useful system is running from day one, just not very well (i.e. the
Smalltalk compiler is broken, the save image menu is broken, the Smalltalk
class hierarchy isn't there, the threading model is broken, the debugger is
broken, etc.). Then you add functionality by either mucking around writing
some statically typed code or, alternatively use Jython (but lose execution
speed), and you rebuild a Squeak-ish system one piece at a time from the JVM
up. So, one day a Smalltalk compiler works (might not even be in Smalltalk
at first, I have a Smalltalk-ish parser already in Jython). Then another day
you can run that Smalltalk code you compiled. Then another day the debugger
starts working. Then you have some nice easy to use GUI classes. Then you
build some simulations to test it. Then you rewrite the Smalltalk compiler
in Smalltalk. Then you reimplement HyperCard but with Smalltalk syntax. And
so on. :-)

--Paul Fernhout



More information about the Squeak-dev mailing list