1) I would like to see a simple demonstration of this, I think while
basically possible, things like traits aren't so easily doable.
Uh, to admit, my above claim is somewhat intuitive.
I have a general understanding of what a prototype based object model
is, and I made a mental experiment what components are needed to support
it, and how these can be implemented in ruby, and I found that they can
be implemented quite easily and naturally.
I don't know what such "subtleties" like traits are. If you gave me a
concise explanation, I'd appreciate that. And then we could think about
my implementation, can/should it be extended to have that feature?
So, my idea is as follows:
A prototype is a module which extends itself.
Cloning is supported out of the box. The good question is inheritance
and that how you realize different method (slot) lookup schemes.
As my prototype is a module, a modification in an instance method is
inherited. You can add/modify methods of a prototype such that its
children are not affected by means of module/singleton methods.
There is also another way of cloning:
module Foo; extend self; end
# Bar will be children of Foo
module Bar; extend self; extend Foo; end
In fact, this is the proper way of cloning. If you do so, sending a
message to Bar which is defined in Foo will be properly dispatched at
Foo. You also get reflection for free: existing methods like
Module#ancerstors will give the correct info here as well.
By mixing in prototypes you gain a nice mechanism to have your prototype
based world interact with traditional ruby code (if it weren't an
important criterion, you could put together custom object models in any
language supporting closures). If you want more, by method_missing you
can make proxy modules to existing objects which give you all the freedom
that you enjoy with prototypes.
You can get your (ie. not basic or third party) classes involved to the
game (of communicating with prototypes, ie. making them possible to be
mixed in; I don't mean here converting them to a prototype based model)
by changing the "class Foo" type opening stanza to "module Foo", and
defining a "new" module method like
def new(*a,&b)
o=Object.new
o.extend self
o.initialize(*a,&b)
o
end
(some subtleties like the "class" instance method need to be worked out
here). Or, you can just use project evil's class-to-module transformer
It's also nice that the initial copy of your prototype can be created in
the usual way, by assigning it to a constant with the
module Foo
...
end
syntax, but copies of it don't need to occupy costants, there you can
use Module.new.
Maybe it would be worth to consider creating a Prototype < Module class
which sugares all these actions (the initialize method of Prototype
would care about the self-extension, etc.)
So, I'm just curious what you think of the power of this approach; is
anything essential missing?
2) And even so, the "class-way" will be too tempting for lack of syntax
sugars, I think.
By my opinion the watershed is not having a class keyword or type or
metatype not, but that in what extent are the important OO mechanisms
(inheritance and co.) are available for "ordinary" objects. By having
singleton methods, the "clone" operation, fully objectified
classes/modules and the possibility of creating proxy modules, the
situation is quite good in ruby.
I don't think of the usual class-based structure as a temptation to
avoid. I do think of prototype-like techniques as a powerful tool which
can be utilized at the right time.
Eg., I tell you about the circumstances amongst which I meditated over
these things.
I was writing a small utility for displaying tree-like structures (in
ascii art in my case, but that could be easily replaced by other
rendering engines, so it's not important). For first, I wrote the code
in mind with that I got serial data to be properly allocated in a fresh
custom structure (eg., reading a directory tree from disk or from the
content listing of a tarball), so I created the necessary classes which
provided this structure.
But then I realized that if I want good, flexible code, I can't exclude
the possibility of displaying something which is not serial, and already
has an implicit tree-like structure (like (nested) Arrays). Converting
such things ("clients") instance-by-instance to my custom structure
(which can be passed to the renderer) is a superfluous overhead. So
rather than doing this, I just wanted to make the implicit structure
explicit by adding the methods to the clients needed by the renderer. I
then converted a bunch of classes to modules, but it was not that easy,
because both class and istance methods were necessary to be added to the
clients to make the renderer happy. The solultion was both extending and
including a module in the client class.
That is, upon necessity, you have alternatives to the stock
"class A < B; include C; ... end; a=A.new" OO. And it's good enough for
me.
I've also seen techniques like self-extending modules, and instead of
having an Foo::Bar type module or class for some task in the context of
Foo, having just a simple Bar object like
module Foo
Bar = Object.new
class << Bar
....
end
in other people's code so I think these ideas are existing ruby
patterns, not just my deviance. Kernel itself is a self-extending
module.
3) Also programming Ruby in this way would likely incur more overahead,
rather than less like in io (I imagine).
I don't think that any of the above would mean an overhead for the
interpreter. As for the programmer, it depends on her needs. If she
wants to use these techniques in a clear, explicit way, she will be able
to add the necessary sugar. Ruby does a good job in this respect.
Csaba