The first sublanguage I implemented is one for prototype-based object orientation, called Sloop.
Sloop was developed in a fully TDD-style and can be found in my darcs repository.
To show its look and feel, we can implement the canonical example of object orientation, an account.
Account = sloop {
self.balance = 0
def_deposit { |v| self.balance += v }
def_withdraw { |v| self.balance -= v }
def_inspect { "#(an account with $#{balance})" }
}
In Sloop, everything is a first-class object, even methods (unlike
Ruby, where only Method
objects are first-class). Instead of
def_inspect
, I also could have written:
self.inspect = Sloop::Method.new { "#(an account with $#{balance})" }
However, the syntactic sugar with def_name
is
nicer to read and closer to ordinary Ruby.
Look how this code is used:
my_account = Account.clone
p my_account
puts "Depositing $10"
my_account.deposit 10
p my_account
On running, you see the expected output:
#(an account with $0)
Depositing $10
#(an account with $10)
The example however can’t fully show the flexibility of the Sloop object system. Have a look at the Circles and Ellipses example.
As you can see, a Circle really is an Ellipse, but they have different implementations! In fact, since we can change the “class” of objects at run-time, we even could cast Ellipses with the same radii transparently into a Circle (the question is “when?”).
The Sloop object system allows for a lot of other powerful things that
don’t fit into this article (and after all, it’s still in
development). For now, I refer you to the source and unit tests.
(You may be curious about the condition
mechanism, for example.)
NP: Spiritualized—I Think I’m in Love