Hi Stevan! Thanks for your informative response. See below for mine.
On Sun, Jun 1, 2008 at 5:19 PM, Stevan Little <[EMAIL PROTECTED]> wrote: > Shlomi, > > On Jun 1, 2008, at 8:57 AM, Shlomi Fish wrote: >> >> I said that I'd like to convert Test-Run to Moose. Well, now I'm in >> the midst of the translation - many tests fail, but the problem is >> that the tests now run much more slowly. It is a noticable difference, >> that makes running the tests unbearable. > > I have found that this is typical of sufficiently complex Class::Accessor > modules, the coding style promoted by Class::Accessor seems to not match > well with Moose. In particular where passing undef values into the accessors > is concerned (which is almost certainly where your test failures are coming > from) Moose will not allow this (a "Str" type is not "a string, but possibly > undef too"). Also proper use of lazy & default/builder with Moose will help > make instance generation quicker, especially in the cases where you don't > always need every slot to be initialized. In those cases too, using the > "predicate" option (documented in Class::MOP::Attribute) will help as well. > Here is an example of this actually: > > Class::Accessor version: > > { > package Foo; > __PACKAGE__->mk_accessors('bar'); > } > > my $foo = Foo->new; # no "bar" initialized > if ($foo->bar) { ... } # this check is cheap, because your just checking > the accessor > > Moose version: > > { > package Foo; > use Moose; > > has 'bar' => (is => 'rw', lazy => 1, default => 'FOO::BAR', predicate > => 'has_bar'); > } > > my $foo = Foo->new; # no "bar" initialized > if ($foo->bar) { ... } # this check is NOT cheap, because your forcing the > deferred value in bar to be created > if ($foo->has_bar) { ... } # this check *is* cheap, because your just > checking slot existence > > Now, in the above example thats not really that much of a difference, but if > 'bar' were are large complex data structure or some expensively computed > value, then it would make a huge difference. > > It should be pointed out that the most recent Moose/Class::MOP release has a > speedup which showed approx. 20-25% better performance, so things are > improving. And people have seen anything from a 3x to 10x times performance > increase by making their classes immutable (depending largely on the > complexity of the classes I think, no one has cared enough to benchmark and > figure it out). > Very interesting. >> The problem as I see it is that I'm using Plug-ins instead of Roles >> and that I didn't finalise the class. Of course, I'd rather not >> finalise the class, or ditch away plug-ins. > > I think perhaps you misunderstand the use of the "immutable" feature. First, > it is not finalizing, in the C# sense of the word, where it prohibits > subclassing and such. Making a class immutable means that the metaclass can > longer be altered, it allows Moose to then create an inlined constructor as > well as memoize several of the more commonly needed bits of data in the > metaclass. This is much less restrictive then you might think, and unless > you are doing lots of ->meta hacking, you will never need to care. Actually, I only use "finalised" because I could not remember the "immutable" term, and was too lazy to look it up. But I meant immutability. I know that what immutability does is as you described, but I don't want that, because I may still want to have further plugins added to the class. > > I am not sure how you are doing plugins, but there are two ways to go about > this in the Moose world utilizing roles. > > 1) Compile-time > > This is plugins that you can know about during class construction time, and > are *class* specific. So you simply create your class, applying the roles > for the plugins. Often times, this is enough and runtime pluggable-ness is > really overkill and not actually necessary. The key thing about this is that > it is *class* specific, meaning you will want several instances of a > specific class (with a specific set of plugins applied to it) in your > application. This may require creating a few extra subclasses, but really > if your application doesn't require arbitrary combinations of plugins > applied to arbitrary instances of varying classes, then this may actually > help increase the clarity of you design. > > Now, since this is all compile-time defined, obviously it does not hamper > making a class immutable. I actually may need to add plugins at run-time. > > 2) Run-time > > Now, sometimes your application design *does* require arbitrary combinations > of plugins applied to arbitrary instances of varying classes, in this case > you really do need a plugin system. In this case you can still use roles, > you just apply them to an instance instead of to a class. Of course this is > a more expensive operation because Moose needs to create an anon-class for > you and apply the role to that, but you asked for it, and so you need to pay > the cost. Moose will cache specific combinations of class+roles and try to > reuse the anon-classes if possible, and it does help if you apply all the > roles at once and not in succession. > > Now, even though this is all done at runtime, you can still make your > underlying classes immutable and get some of the performance benefits it > provides. > I see. > >> And naturally, Moose is >> also making many run-time checks that are not present in my old >> Class-Accessor and are not really necessary for me. As much as I >> appreciate type-checking for instance members, I'm disciplined enough >> for it not to matter much. > > So just remove the types, it is that simple since they are entirely > optional. In fact, the accessor generated by Moose for this: > > has foo => (is => 'rw'); > > if *faster* the the typical Class::Accessor version since it never creates a > lexical $self, and just uses $_[0] instead. Moose does as much as it can to > only make you pay for the features you use, but it cannot remove the cost of > features you use, but just don't really want ;) > Yes, but to me it seems that it beats the point of using Moose. If I'm using Moose, I'd rather have type-checking, so people will know what every class member is. >> So Moose seems impressive, but an overkill for Test-Run's needs. > > I think perhaps you have not given Moose enough of a chance, and that your > making this judgement before properly understanding what Moose can provide > for you. Any powerful tool (like Moose), if not properly used, will seem > like overkill. Ah. > >> So unless Moose will become faster, I won't be able to use it in >> Test-Run, and will have to rely on Class-Accessor and the additional >> logic I've built on top of it. > > Moose is becoming faster and that is one of our primary goals right now. > However in your case, by using type checks you don't want and not making > your classes immutable, *you* are the one slowing your application down. The > tools are right in front of you, you need only to use them. OK. > >> From what I've heard of CPython, they >> often re-implemented Python libraries code in C to make them faster. >> Perhaps the Perl world should follow suit. > > We have some C/XS in Class::MOP and the inclusion of that it provided our > last major speed boost actually. There are possibly a few other places we > could recode in C/XS that would provide us some more benefits, but since I > am not (and never will be) a C programmer, all I can say is > > ... patches welcome :) Well, I'm a C programmer, but not much of a PerlXS programmer. I've read "Extending and Embedding Perl" (E&EP) once upon a time, but forgot it, and found it a bit deficient. I also downloaded its PDF from eDonkey, so I can use it as a reference. I also started writing http://opensvn.csie.org/shlomif/documents/perl/trunk/perl5/ext-embed-internals/ But have neglected it. The core XS documentation is very hard-to-understand. I'd love to be able to write XS properly some day, but it will take some time. ----------- Back to the topic: I still feel that Moose is a bit unsuitable for the style of OO I used in Test-Run. Regards, Shlomi Fish