From: Csaba Henk Date: 2005-01-25T01:40:54+09:00 Subject: Re: Self and Ruby Comparisons On 2005-01-24, Trans wrote: >> Btw, I hope you know that Ruby has almost full support >> for prototype based programming. > > 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