This post originated from an RSS feed registered with Ruby Buzz
by Christian Neukirchen.
Original Post: The T Object-System (in Ruby)
Feed Title: chris blogs: Ruby stuff
Feed URL: http://chneukirchen.org/blog/category/ruby.atom
Feed Description: a weblog by christian neukirchen - Ruby stuff
T is a dialect of Lisp derived from Scheme. It is comparable in
power and expressivness to other recent Lisp dialects such as Lisp
Machine Lisp, Common Lisp, and NIL, but fundamentally more similar
in spirit to Scheme than these other Lisp dialects.
T is an attempt to create a powerful and expressive language which
is portable, efficient, and suitable for a broad variety of
applications, including symbolic, numerical, and systems
programming.
T draws from many sources in its attempt to provide a complete yet
simple and unified system. For the most part, the language’s
designers are collators, not originators. Common Lisp, NIL, and
Scheme have been the strongest influences.
The manual contains a lot of interesting stuff, the one I found most
interesting however is T’s object-system. This object system is so
easy (one could say trivial), but still so powerful and flexible that
you just need to admire it.
Basically, there are two procedures to implement the T object-system,
OBJECT and OPERATION. OBJECT takes two parameters, a value proc
that gets called if the object itself gets called (I leave that out in
the Ruby version, since it only makes sense with Lisp-1s and rarely
has an use anyway), and a list of handlers, each element consisting
of an symbol and an lambda. OBJECT returns a new object that
responds to the handlers given.
In my Ruby re-implementation, we would write:
# An object responding to `op'
obj = TObject.new(:op => lambda { |s| 34 })
obj.op # => 34
The first parameter of the lambda is used to pass
self, but you
can pass several arguments, of course:
# An object responding to `op'
obj2 = TObject.new(:op => lambda { |s, x| x })
obj2.op(55) # => 55
As you can see, we already have polymorphism. So far, this is not
very spectacular, though. The really interesting things about the T
object-system are operations and joins.
T operations are like methods of Object in Ruby. They are used as a
default everywhere except you did override them (In my Ruby
reimplementation, operations are only defined for TObjects, not for
every datatype as in T):
# An operation to do `op'
TObject.operation(:op) { |s|
:zebu # By default, return :zebu
}
TObject.new(:op => lambda { |s| :quagga }).op # => :quagga
TObject.new({}).op # => :zebu
So far, the object-system is rather boring, there is no real
instantiation, no mixins, no singleton classes, all the cool stuff
from Ruby is lacking. :-) Enter JOIN, it takes an unlimited number
of objects and combines their behavior:
Now, I can’t think of anything (except method_missing, which easily
could be handled as a special-case) that’s possible in Ruby’s
object-system, but not T’s.
(You may argue that the T object-system lacks instance variables, but
those can easily be replaced with accessable closures, which both T
and Ruby have.)
Another nice thing about the T object-system is that it’s soo easy to
implement (20 lines of Ruby), that you could quickly write it in
low-level lanuages as C as a foundation for a future programming
language.
By the way, here is the T object-system in Ruby:
class TObject
attr_reader :handlers
@@operations = {}
def self.operation(name, &block)
@@operations[name] = block
end
def self.join(*args)
TObject.new(args.inject({}) { |a, e| a.merge e.handlers })
end
def initialize(handlers)
@handlers = handlers
end
def method_missing(name, *args)
(@handlers[name] or @@operations[name]).call self, *args
end
end