in reply to Re^8: Data Structures
in thread Data Structures

I'm not even anti-Moose. It is without any doubt the very best of the OO modules around.

Wait, your confusing me now :P

And (if it ever compiles for Win32), ...

The guys over at Best Practical are trying to replace all my XS usage with Pure Perl alternatives, so that may happen soon. Although I have to wonder if you have tried it on Strawberry Perl yet? I have heard of some people having success with that (we currently have a broken test on windows, but its the test, not Moose).

... whenever I have an application for a module that will benefit from OO, I will seriously consider using Moose.

Oh, please do, I would love to convert you :)

This exercise caused me to look deep into the guts of the beast and I am seriously impressed by both what it does and the way it does it.

<being_serious>Thanks, that actually means something coming from you given the depth to which you tend to analyze and look at stuff</being_serious>. Be careful though, Moose-guts tend to stain and are really smelly if you leave them out for too long.

I'm less impressed with some of the dependancies and the choice to use them. A couple of modules (IMO) substitue a module, a use line and a complicated line of code (in the calling program, and a lots of often unnecessary code in the module itself) for a rather simpler, single line of core perl code.

Could you be more specific as to what you mean? I would happily remove a dependency if the replacement were as simple as that.

Contrast that with facing the problem of refamiliarisation with Moose's 20+ modules and reams of documentation six months from now.

FWIW, to use Moose, you really just need to read the Moose::Cookbook, and the POD of Moose (maybe a little in Class::MOP::Class and Class::MOP::Attribute too, but we are gonna move the relevant bits up to Moose soon). If you want to use roles, then you need to skim the POD of Moose::Role too, but you will find it is very similar to what is in Moose. If you want to use types, you need to read the POD for Moose::Util::TypeConstraints. Everything else (especially everything in Moose::Meta::*) is optional, unless you want to dig into the MOP, in which case your needs are becoming quite complex and so you should expect to have to read 20+ modules worth of docs (and maybe even a book or two) to use it properly.

-stvn

Replies are listed 'Best First'.
Re^10: Data Structures
by BrowserUk (Patriarch) on May 08, 2008 at 12:15 UTC
    Wait, your confusing me now :P

    :) I'll take it that this is now redundant. My objections are not "whether" OO or Moose are useful, powerful desirable. Just when.

    And the 'bugs' I alluded to were purely hypothetical. The point being that as systems become more complex, the costs of managing and negotiating between the sub-component authors grows exponentially. Users of complex systems have to take that into account when deciding if the benefits of re-use of those complex systems outweigh the costs to them. Including when things go wrong inside those systems.

    If a users application requires, and will benefit from, a large proportion of the features--code generation, introspection, etc.--that Moose provides in buckets, then it's a no-brainer to stand on the shoulders of those that write and maintain that complex, powerful and well-designed system, rather than starting from scratch.

    For the OPs application, as described, I do not think those criteria are met.

    The guys over at Best Practical are trying to replace all my XS usage with Pure Perl alternatives,

    Whilst I think that Pure Perl alternatives have some merit, I also think that the (further) performance hit of removing all the XS code from Moose would be a mistake. Most XS code will compile on Win32/AS, with only minor changes. The difficulty is in locating them.

    Oh, please do, I would love to convert you :)

    I don't need converting to the benefits of OO--used appropriately. As far as Moose is concerned, I'm already convinced that is is "best of breed" for projects requiring its featured. Far better than most everything else in the Class::* and Object::* name-spaces.

    Could you be more specific as to what you mean? I would happily remove a dependency if the replacement were as simple as that.

    It's not just about simple substitution. It also about choosing to use some of them.

    • Sub::Uplevel

      From the Caveats:

      Well, the bad news is uplevel() is about 5 times slower than a normal function call. XS implementation anyone?

      Perl's function calls are already slow. Moose places (of necessity for its function) many extra layers of function call over raw access. Rather than adding another layer, who's only purpose is to deceive, it would far better (for everyone) to give full traceback (ala Carp cluck/croak)), than to impose the performance & misinformation penalties of "hiding the truth".

    • Sub::Exporter. a sophisticated exporter for custom-built routines.

      There's a lot going on inside this module. That's a result of the power of the features it can provide.

      The question is: Is Moose using or benefiting from that power? Would Exporter or Exporter::Lite, or even just a custom import() serve Moose equally well for its needs, and avoid some of the overhead?

    • Sub::Name -(re-)names a subroutine.

      What does return subname 'Moose::Role::extends' => sub {... }; buy you that

      *Moose::Role::extends = sub{ ... }; (or even: sub Moose::Role::extends {...} doesn't?

      (I think I may understand the reasoning behind not using the latter, but better that you decide one way or another yourself

    FWIW, to use Moose, you really just need to read...

    Sophisticated systems require a good deal of good documentation. My comments were simply to defuse the notion that use of accessors/getters simplifies maintenance of nested, built-in data-structures.

    The question here is: do you need or benefit from the sophisticated system (for your specific application)?.

    For this application, loose wrappings around built-in data-types, my conclusion is no. That in no way detracts from Moose when used for that for which it is intended.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Sorry, been meaning to respond for a while, but been busy. I do agree with you that if OO is not appropriate, then don't use OO. I have been a huge fan of functional programming for a while, and honestly if I could use OCaml/LISP/Scheme/etc for $work, I would, but there is basically no decent libraries and lots of academic "abandonware". That said I am also not a big fan of YAGNI, and since at $work we typically maintain our apps as well as write them, I prefer to treat even small projects as if they might grow large (which they typically do, at least for us). But anyway, this is all a matter of style and environment. So let me just address the dependencies you listed.

      Sub::Uplevel

      This is not my dependency, but a dependency for Test::Exception, which I consider a key part of any good testing toolbox. So that one is not going anywhere unless the Test::Exception author removes it. Moose does not ever use it itself.

      Sub::Exporter

      Well to start with, Exporter is gotta be the biggest piece of bloatware in the perl core modules. I hate that module with a passion, just thinking about how bad it is makes my skin crawl. I never cared for Exporter::Lite either, it is better, but really the @EXPORTS and @EXPORTS_OK stuff is that makes me stay away, I don't like having to make public variables to export stuff.

      Sub::Exporter on the other hand is awesome. Not only is just for exporting subs (who the hell exports variables anymore really), but it can do all sorts of fun tricks. You couldn't do this with Exporter:

      package LOL::Cat; use Moose 'has' => { -as => 'i_can_haz' }; i_can_haz 'cheeseburger' => ( is => 'rw', trigger => sub { print "NOM NOM" } ); LOL::Cat->new->cheeseburger('KTHNXBYE');;
      Really, I think Nuff said there :P

      Sub::Name

      Well first let me say that we have made this dependency entirely optional now as part of the whole "make XS optional" thing that the Best Practical people asked for.

      What does return subname 'Moose::Role::extends' => sub {... }; buy you that *Moose::Role::extends = sub{ ... };
      To start with the CV will still have the name "__ANON__" and will not seem to come from the "Moose::Role" package (unless you did that code within the Moose::Role package itself). I think that it is important to maintain this internal consistency when building classes. But anyway, it's optional now so you can skip it.

      -stvn

        Starting at the end (cos the the challenge was interesting:).

        Sub::Exporter on the other hand is awesome. ... but it can do all sorts of fun tricks. You couldn't do this with Exporter:

        Who needs Exporter :)

        package LOLCat; use pudu 'has' => { -as => 'i_can_haz' }; i_can_haz 'cheeseburger' => ( is => 'rw', trigger => sub { print "NOM NOM" } ); 1;
        #! perl -slw use strict; use LOLCat; LOLCat->new->cheeseburger('KTHNXBYE'); __END__ c:\test>t-pudu.pl NOM NOM

        And what is actually required inside pudu.pm to make that happen?

        It's minimal, just enough to meet the requirements of the challenge, but I hope it is enough to show that much of what Moose does, could be met without large dependency chains, and rather more efficiently. (Especially once you drop the need for bondage and discipline!)

        I guess that sums up my feelings about a lot of this kind of module. (Sub::Exporter et al.) At their core, they provide a single, useful mechanism. But then, almost inevitably, they feel the need to add to that basic mechanism a bunch of "fun tricks", which whilst fun, often aren't required by most of their users. And the provision of those additional features, as much for the sake of having something to put in the POD as anything else, leads to complexity and bloat. Not just because of the presence of the additional code to provide those extra, little-used features. But also in additional code in the core, oft-used features in order to support the little used ones. With the result that code that only needs the core, useful mechanisms is often paying a penalty for the support of features that they don't use.

        For the authors of these modules, they only test & benchmark their code from one level above, and the penalty seems minor. But once you get to the level of a complex framework like Moose, that utilises several of this type of module, and uses two, three & four levels deep chains of them, each adding its own layer of "fun tricks" and their associated (unnecessary) overhead, the individually small deltas start to add up.

        Now imagine me writing my graphics application using Moose. I have a hierarchy of classes: Solids inherit from WireFrames inherit from Lines inherit from Point3D; and the core of my application is doing hidden Line and hidden Face removals on complex Solids before rendering to a View2D--the very stuff where Class/Object mechanisms like Moose are at their most useful and productive. And at each layer of my application I'm picking up the products of the deltas below Moose and compounding them over the layers of my application above Moose.

        The result is that small, negative performance delta don't just add up, but multiply up, and my app is running 2 or 3 or 4 times more slowly because of the presence of features in the lowest levels that I, nor most other Moose users will ever use.

        If you are really up for a challenge?

        tos recently posted a behemoth of a piece of really quite awful code. (No disrespect meant tos. Its given me hours of fun exploring it). It sets out to be OO, but throws everything into one huge file because he's taken a bunch of short cuts (global vars mainly) to work around things he didn't understand how to do using Perl's DIY OO mechanisms. I had a couple of attempts at splitting it up into modules and making it work, but never really had the motivation to see it through.

        It runs a 3D Rubix Cube (3x3, 4x4 or 5x5) simulation using Tk as the display tool, making extensive use of OO (mostly) to perform the math. It runs, in its presented, messy, badly structured form, with a surprising turn of speed. You can spin and rotate the cube in 3 dimensions using the mouse, and (when it doesn't crash) the graphics keep up with you.

        The challenge is for us to agree the Moose-style class definitions for the 8 classes required by the Rubix Cube application:

        package matob; package point3d; package line3d; package vec3d; package rect3d; package cube3d; package slice; package qb;

        and then you port it to Moose and I'll extend pudu just enough to meet that specification. We could then compare, from all aspects, the results.

        I realise that this is more than just a couple of hours work and that you're a busy guy, busy doing $work and maintaining Moose. But the results would make for a very good demonstration of the power of Moose (he said trying to tempt :).


        (*)I mentioned "bondage & discipline" above. I realise that this is what a lot of your customers are asking for, and you are supplying that need. I did start to question that need here, but decided that it was irrelevant to the subject and besides, I feel a meditation on the subject coming on, so I've deferred that for another thread. And for the record. The more I learn about what Moose does (and the way it does it for the most part), the more impressed and enthralled I am by it. I'm even more impressed by what you and your team have pulled together so quickly.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.