I seem to have been missing in action for the best part of six months so
I thought it was about time I put together a progress report and pimped
the vapourware in hopes of finding some likeminded
miscreants/dilettantes to turn it into something more substantial.
There’re probably only a handful of people on here who’ll be interested
in what follows so I’ve marked it OT for those of you interested
exclusively in Ruby. Feel free to press delete, I won’t be offended
== BACKGROUND ==
For those of you without long memories, a quick recap. At the tail-end
of last year Google released their Go language (http://www.golang.org)
onto an unsuspecting world. The brainchild of Rob Pike and Ken Thompson,
Go’s sort of a reworking of Limbo from Plan 9/Inferno with baked-in
concurrency and an inside-out approach to object orientation.
As those of you who’ve had the dubious pleasure of either sharing bar
space with me or sitting through one of my conference sessions on Ruby &
Unix, for all that Ruby’s my language of choice I still spend a fair
amount of time grubbing around in the C world. Love them or loathe them,
there are times when we all need systems-level languages to efficiently
solve certain kinds of problems.
The longterm goal of RubyGoLightly is to make Ruby a first-class citizen
in that sense, moving systems coding firmly and permanently into our
high-level world. I know it can be done as Ruby’s pretty much as
flexible as Lisp and Symbolics proved that an OS could be written in
Lisp with minimal dependence on assembly language. So the aspiration
isn’t so lousy even if I’m far from certain that I’m personally capable
of achieving it.
There is however one major roadblock to turning Ruby into a systems
language: existing runtimes just aren’t written that way. The closest we
have at present is JRuby, and even there if you want complete control
you still have to step outside of the Ruby mindset and hack Java, JVM
bytecode or probably even write JNI extensions in C.
Then there’s the question of an optimal Ruby runtime. There’s a lot of
implicit concurrency in the average Ruby program which to the best of my
knowledge isn’t being addressed by any of the existing implementations.
We live in a multicore world where it’s only natural that collection
enumerators etc. should be exploiting those cores for cheap scalability.
Admittedly writing concurrent systems in C can be a right pain in the
arse, and even in Java there are subtleties arising from the
architecture of the JVM so I’m not levelling criticism at anyone. It’s
just a fair observation that if I have four processor cores and a list
with 10K entries that map/reduce algorithms should use all four cores if
at all possible and return their results in approximately 1/3rd the time
of a naive sequential implementation.
Given that Intel are playing with 80+ core processors in the lab - and
that modern graphics cores have even more available horsepower via
OpenCL - there’s clearly an opportunity worth investigating.
Go does concurrency pretty well, especially considering that the runtime
is still in its infancy and will probably undergo considerable
optimisation in the future. It’s basically an implementation of Hoare’s
CSP so all the tricks that can be used in Occam etc. for clean
concurrency can be used in Go, and whilst it doesn’t yet support OpenCL
that’s just a matter of time and a sufficiently nasty itch being worth
Another desirable trait for a Ruby runtime is decent browser
integration. I get really annoyed having to write heavyweight
probably never recovered from my painful experiences with NewtonScript
as I find the entire Self language family unbearable, and the same goes
for the slot-based GTK GUI stuff (sorry webGTK). Go has support for
Google’s Native Client so is ideal for injecting native code into web
content, including a Ruby runtime were it to exist. I love that idea.
Write your whole web app in Ruby, with identical abstractions.
The same thing could be achieved using a Ruby runtime written in
Basically writing any significant runtime platform is a significant cost
and taking anything beyond the complexity of a simple bytecode
interpreter means months of full-time hacking and serious cogitation.
The final thing in Go’s favour is that it can compile to native code for
bare metal - i.e. no OS at all, just a bootloader and an executable.
I’ve yet to play with that side of the language, but having written
assembler for embedded systems with no OS I would love to see a Ruby
runtime deployed in the same manner. From there it’s a short step to an
OS written in Ruby, and that means an OS any half-competent programmer
could understand in detail.
My colleague Romek and I have been boring people with that idea for
about five years now, and mad though it probably seems I still believe
it’s a goal worth pursuing.
Anyway, to recap: the world might be a better place with a Ruby runtime
that embraced pervasive concurrency in the runtime implementation, that
was platform agnostic, and that allowed systems-level coding to be
performed with the same ease we associate with Rails or even Sinatra. I
won’t pretend RubyGoLightly will tick all these boxes - right now it’s
an idea and ideas are by their nature transient. However it is certainly
a framework in which to explore whether such a Ruby is possible.
== GoLightly ==
There are two aspects to this project. One is the Ruby runtime, which
right now I have only the vaguest of ideas about how to implement. I’m
following a hunch that a Forth-like Threaded Interpreter might allow
optimisations that we’re not going to see with mainstream bytecode
interpreters and a lot of current effort is devoted to writing such a
Forth implementation. Although I hesitate to call it Forth given the
usual expectations of F79, F83, figForth or ANS94 compliance - none of
them particular of particular importance.
Threaded interpretation isn’t a million miles removed from the naive
view of Ruby’s object model so I’m hoping my current work will generate
insights relevant to that, however its main purpose is to drive design
of the GoLightly virtual machine which is an abstraction of the kind of
hardware I’m interested in seeing Ruby run on.
There’s an early branch of GoLightly on github
(http://github.com/feyeleanor/GoLightly) which exposes some basic
despatch loops (inlined bytecode and indirect function call) and a
preliminary model for SIMD-style opcodes for basic vector processing and
a supporting register model.
There are a few examples of hand-coded assembler in the tests to give a
feel for the machine language along with some micro-benchmarks for
anyone who fancies playing. GoLightly already copes with multiple
virtual processors, all working on their discrete problems but there’s a
lot of work yet to be done in inter-core communication, the memory
allocation model, and parallelising SIMD instructions.
One of the few things I dislike about Go as it currently stands - and
which alas is considered a strength by the core team so is unlikely to
change - is that the language doesn’t support a representation-agnostic
datatype suitable for holding bit-strings: basically numeric types
always convert their contents to suit the type to which they’re being
coerced, or else a panic occurs. Getting around this involves playing
games with pointers that make a fair amount of (void *) usage in C look
clear and reasonable. The justification is that this sort of thing
shouldn’t be encouraged (with which I happen to disagree anyway) and
that the extra pain is a bit of nudge to prevent it. I’ll keep raising
the issue with the core team every few weeks as I personally believe
maintainability is much more important than type safety: after all, we
can always write tests…
Anyway GoLightly is stalled whilst I evolve a reasonable API for
handling bitstring manipulations, which is proving a subtly intractable
problem. I’m hoping that hacking together a few languages will help me
figure out most of the implementation details which are currently
eluding me and then I’ll roll a bitstring library back into the Go core
library if the team will have it.
The unnamed Forth I’m currently working on is running into the same
problems, but I’m still hoping to get a reasonable build ready for
release on github over the summer. So far I have a good first cut of a
compile/execute/decompile model which supports dynamic coding and I hope
to reduce much of the Go code for implementing a core vocabulary to
GoLightly-style bytecode. These bytecodes (which are effectively unique
to the currently running system, so more a dynamic object code than a
formal bytecode) would themselves be a first-class element of the
language so that’s an interesting model for both a native code interface
and for allowing inline use of multiple languages.
== The Roadmap ==
From Forth to Ruby is one hell of a leap, and whilst I don’t doubt it
can be done in one step there are other problems I want to solve along
I definitely see a simple Lisp being in the mix as I’ve always felt
there is an equivalence between Forth and Lisp which goes unremarked: I
guess there aren’t that many people who’ve hacked with both, let alone
who’ve written runtimes for both. Lisp will be the testbed for doing
standard function call stack allocations and a few other aspects of
implementing a high-level language which Forth skirts. Common Lisp it
most definitely won’t be though (or Arc for that matter).
From there I want to get a Scheme working, mostly to figure out how to
handle tail-call recursion efficiently. It could be that this will be a
specific compiler optimisation required separately for each supported
language, but I’d really prefer it to work at the object code level so
that it’s applied across all compiled code automatically. Go uses
relatively small stacks to improve concurrent performance compared to
pThreads and whilst GoLightly threads are currently specced to use their
own user-space threads I’d like to move beyond that in the future so
tail call culling will be essential to not swamping the runtime stack.
After Scheme I’m hoping to implement a simple Logo system to get a
handle on the interfaces offered by Google’s Native Client etc. - it’s a
bit of a gratuitous diversion as Logo is hardly a mainstream language,
but the underlying structure is similar enough to Lisp that I think it
will be an easy build and there’s been some interesting work in
Logo-land to do with multi-threaded graphics which might have
interesting tie-ins with OpenCL.
Much of the impetus to start hacking on RubyGoLightly is thanks to
TinyRb, a really sweet subset of Ruby running on a Lua-style VM. Once
I’ve solved the main runtime problems addressed by the Lisp arc of
languages I plan to write a runtime interpreter for the TinyRb bytecode
so its compiled form can run natively in GoLightly. My gut instinct is
that this will be a great starting point for runtime optimisations that
apply to a richer subset of Ruby.
At LSRC last year I showed off some of the code from a port of SQLite to
Ruby that I was working on at the time. That project got put on hold
when I started RubyGoLightly but given that SQLite is a really sweet
engine and internally uses a register based VM it’d be easy to port to
GoLightly and provide something like CoreData out of the box.
There could be a few steps after this: for one thing I’ve this gut
feeling that doing a dirty implementation of Io could be instructive,
though I can’t really explain way. Something to do with the method
passing semantics. A roadmap’s no good if it doesn’t allow for
However the ultimate destination is RubyGoLightly, the Ruby runtime that
scratches the itch of using Ruby as a systems language. No promises
about where or when, and very few about how… but I promise to check in
with another status report in a few months that will hopefully be more
In the meantime, happy hacking,
Games With Brains
raise ArgumentError unless @reality.responds_to? :reason