Re: Moosifying Test-Run Part 2: Probably Not

[email protected] ("Shlomi Fish")
Newsgroups perl.moose
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.