in reply to Re^4: Reopening builtin classes, redefining builtin functions?
in thread Reopening builtin classes, redefining builtin functions?

Lemme start by saying, I am not looking for a Ruby v. Moose flamewar. I like Ruby a lot, in fact it inspired some parts of Moose (the other parts were inspired by 2 of Ruby's inspirations, CLOS and Smalltalk). You asked for details, and I am am giving you them.

I have no idea what you're going on about with "meta-circular MOP"

The MOP (or Meta Object Protocol) is basically the "API to the Object System". The Ruby equivalent of a MOP (there is no formal complete one, but a collection of bits which can be roughly called a MOP when smushed together), is a combination of the ObjectSpace, Kernel modules, the Class, Object and Module classes. A MOP provides a means with which to introspect/reflect and in some cases alter the internals of the languages object system. There are a few different kinds of ways to approach building a MOP, the two I am most familiar with are the meta-circular style (see CLOS) and the non-meta-circular ones (Pythons metaclasses could be described this way (last time I looked) and some C++ metaclass systems as well).

A non-meta-circular MOP is one where the Class is an instance of a MetaClass, and the MetaClass is an instance of a MetaMetaClass, etc etc etc. This can go on forever and is sometimes called "turtles all the way down". You basically decide at which point your system "ends" and then that layer just magicaly springs into existence and there is nothing beyond it. Ruby's object system is kind of like this, the Class and Object spring into existence in object.c and a metaclass is not exactly an instance of Class, but instead a kind of odd specialty "singleton class". Ruby borrows heavily from Smalltalk here in that metaclasses are implicit and there is a parallel metaclass hierarchy that matches the class hierarchy. Because metaclasses in Ruby are implicit, you have little control over the creation of them, the best you can do it alter them once they exist by adding singleton methods to them (which is what you basically do when you mess with class <<self; self; end).

A meta-circular MOP is one where there you have "tied the knot" or "bootstrapped" the system together. This is done by making the class Class itself an instance of Class (note the capitalization here). The result is you end up with a nice little loop at the top of your object system and you suddenly have a system which is implemented in itself. Meta-circularity is a common thing in the LISP and Scheme world where there is such a blurring of code and data that it is easy to write things like a LISP interpreter in LISP. Meta-circularity allows you to easily extend your systems with the system itself, see my previous example in which I basically extended the behavior of Class. (Yes, in Ruby you have open classes, so it is possible to extend Class, but its a global change, which brings with it a whole slew of problems). Like I said before, it's hard to give a really practical (yet simple) example of how metaclass programming can be helpful because they contain the power to alter the behavior of the very core of your object system, and thats just not simple stuff.

Your example requires no metaprogramming in Ruby

I almost supplied pretty much that same code for a Count module, but I decided against it. (You can do the exact same thing in Perl using a package level variable as a counter, although the lack of consistent OO makes wrapping &new a little trickier, but still it does work). Like I said above, the example is basically too simple and metaclasses are not usually simple things.

Regarding the attribute protocols, it looks like Ruby's attr_accessor with some extra checks tossed in.

It is similar to Ruby's attr_accessor but not exactly. Ruby just stashes information into the class about each attribute (usually just a string name) and then the methods are just added to the class normally. Moose does it differently, it treats attributes a first-class elements in the object system so each attribute has it's own meta-object to back it up. These attribute meta objects are fully introspectable, and can be customized on a per-attribute basis (you can have several different custom meta-attirbutes in a single class). You can get all sorts of practical stuff with custom attributes, take a look at MooseX::Getopt and MooseX::AttributeHelpers for just a few examples.

There are third party libs out there to do this for Ruby, but it's trivial to roll your own.

I don't know many of these 3rd party libs you speak of, so perhaps there is some cool stuff I am missing, Links would be helpful. As for rolling your own, just a trivial accessor generation system is trivial (see all the crap that is on CPAN), but Moose attributes are so not trivial. Just flip through some of the examples in the cookbooks to see what it can do, like lazy initialization, easy to use (but really powerful) delegation, type checking and coercion, all sorts of stuff. And Moose and Class::MOP are really well tested with over 150 test files and 4000 unit tests between them, so why re-invent that wheel?

Lastly, I don't know what CPAN has to do with this discussion.

You asked what Moose can do that Ruby cant. Moose can easily use the accumulated knowledge and battle tested code of CPAN. In fact Moose was built specifically to play well with existing Perl 5 code bases and not require too huge a change.

Anyway, so thats it. The differences are subtle on the surface, but fairly radical if you go deeper down. Of course if you don't care about any of that shit, then feel free to ignore me.

-stvn