Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re: curried-up moose

by rodd (Scribe)
on Jan 18, 2009 at 13:15 UTC ( [id://737145]=note: print w/replies, xml ) Need Help??


in reply to curried-up moose

Well pobocks, you're right, I guess having eyes attached to legs is not the best example. But basically I was just trying to exemplify the adding of parts to a body, then accessing those parts in any order with a single $body object instance. The package SOAP::Lite is a perfect example of stacking calls, even though I seldom use that kind of design.

stvn, I think "subclasses" could be the right word, given eyes are a body-part and inherit the 'blood pressure' attribute from the body, even though they could be implemented as inner classes as well. But definitely currying is not what I meant, so I take it back. Anyway, I came to this question while prototyping proof-of-concept code in Moose, starting with object usage in the final code and a simple does-it all class. I was researching a way to represent a DOM-like objects quickly without so many subtypes and with as little keystrokes as possible. I didn't know yet where all the pieces would fall, so I might write the eyes code before I have a head or a leg for that matter.

So this is not about my app design, which I've just started. It's that I really enjoy brainstorming with Moose, so after writing up around 20 lines of candidate has attributes, I saw myself writing another 20 arounds and, as a lazy programmer that I am, I was asking myself if I was missing something, on the lines of:

has 'eyes' => ( is=>'rw', chained=>1, ... ); ## or has 'eyes' => ( is=>'rw', isa=>'Chained[HashRef]' );

I'm glad to hear the Moose team is looking into that. At the end of the road, I'm just trying to replace my old style of prototyping with a big & ugly sub AUTOLOAD { ... } directive with something a little more readable and extensible, just in case the prototype prospers.

Replies are listed 'Best First'.
Re^2: curried-up moose
by stvn (Monsignor) on Jan 18, 2009 at 15:25 UTC
    I think "subclasses" could be the right word, given eyes are a body-part and inherit the 'blood pressure' attribute from the body,

    Actually, I would be more inclined to do that relationship with delegation instead of inheritance as i assume blood pressure would be an active changing value of the instance and not a static value of the class. Something like this perhaps:

    package CirculatorySystem; use Moose; has 'pressure' => (is => 'ro', isa => 'HashRef[Int]'); package Eyes; use Moose; has 'body' => ( is => 'rw', isa => 'Body', weak_ref => 1, # cycles are bad handles => [qw[ blood_pressure ]] ); package Body; use Moose; has 'circulatory_system' => ( is => 'ro', isa => 'CirculatorySystem', handles => { blood_pressure => 'pressure' } ); has 'eyes' => ( is => 'ro', isa => 'Eyes', trigger => sub { my $self = shift; # must hook up new eyes # to the body ... $self->eyes->body($self); } ); package main; my $nexus_6 = Body->new( eyes => Eyes->new, # i make your eyes! circulatory_system => CirculatorySystem->new( pressure => { systolic => 112, diastolic => 64 } ), ); print $nexus_6->blood_pressure; # is the same as ... print $nexus_6->circulatory_system->pressure; # is the same as ... print $nexus_6->eyes->blood_pressure;
    This way when the pressure of the circulatory system changes, it is reflected in the blood_pressure method of all the other body parts.

    ... so after writing up around 20 lines of candidate has attributes, I saw myself writing another 20 arounds and, as a lazy programmer that I am, I was asking myself if I was missing something,...

    I wonder if you are familiar with the array-ref versions of both has and around?

    has [qw[ eyes ears nose mouth ]] => (is => 'rw'); around [qw[ eyes ears nose mouth ]] => sub { ... code to make accessor +s return $self here ... }
    Of course you can't get very specific in your has definition, but if you are just prototyping it can be a very useful feature and is easily refactored later on. And also remember that the Moose sugar is only just perl functions, so you can just as easily do this:
    my @parts = qw[ eyes ears nose mouth ]; has $_ => ( is => 'rw', predicate => "has_$_" ) foreach @parts;
    The same also works for before/after/around as well.

    -stvn
      Nexus6! LOL! :D

      Thanks for the example. I completely ignored the usage and conceptual power of handles. In fact, handles is a dish I haven't learned to cook. Is there a recipe for it in Moose::Cookbook? Can't find it. Well, in any case the section on handles in the Moose.pm POD is extensive and I'm reading it over as I write this.

      BTW, the POD mentions a tree example built with handles that would become a recipe, but in the binary tree recipe handles are not used at all. Maybe this "build your own Nexus6" could become a recipe for it.

      around [qw eyes ears nose mouth ] => sub { ... code to make accessors return $self here ... }
      I had completely overlooked the existence and possibilities of the array-ref feature in prototyping. That's a great golf tip. Nice. Just one thing, it looks like
          around [qw[eyes ears nose mouth]]
      won't work. It should be just a straight array such as:
          around qw[eyes ears nose mouth]

      Anyway, your example of using handles for delegation will probably answer most of my chaining needs, but I'd still don't get the subtleties of using handles against using MooseX::CurriedHandles --something I'll look into carefully soon.

      Also, defining relationships --from body to eyes and from eyes to body-- seems a little wordy to me. How about this:

      package Body; use Moose; has 'eyes' => ( is=> 'rw', isa=> 'Eyes', metaclass=> 'MooseX::NestedPackage', class=> q{ has 'color'=> (is=> 'rw', default=> 'blue'); } ); package main; my $body=new Body(); ## gets new eyes too print $body->eyes; ## and they're blue $body->eyes(new Eyes(color=>'brown')); $body->eyes->color('green');

      Would this syntax be way left field? The extension looks like this (with some quite ugly eval's there).

      package MooseX::NestedPackage; use Moose; use Moose::Util; extends 'Moose::Meta::Attribute'; has 'class' => (is=> 'ro',isa=> 'Str'); after 'attach_to_class' => sub { my ($attr, $class) = @_; my $name = $attr->name; # 'eyes' my $class_name = $attr->{isa}; # 'Eyes' my $class_code = $attr->class; # all the antlers my $parent = $class->{package}; # 'Body' my $parent_lc = lc($parent); #'body' $attr->{trigger} = sub { my $self = shift; $self->$name->$parent_lc($self); }; my $code = qq{ package $class_name; use Moose; $class_code; has '$parent_lc' => (is=> 'rw',isa=> '$parent',weak_ref=> 1); }; eval $code; $@ && die qq{ $@:\n$code }; ## default is not needed $attr->{default} = sub{ $class_name->new() }; ## cos defaults should go directly in each nested attribute $attr->{lazy} = 0; ## lazy stopped working outside due to a missi +ng default };

      -rodrigo

        In fact, handles is a dish I haven't learned to cook. Is there a recipe for it in Moose::Cookbook? Can't find it.

        Nothing that specifically does "handles" only, but Dave Rolsky (one of the core Moose team) currently is working on a whole new set of Moose docs through a TPF grant, I suspect he will have something nice in there.

        BTW, the POD mentions a tree example built with handles that would become a recipe, but in the binary tree recipe handles are not used at all.

        Yes, that became Forest::Tree instead, specifically the 'parent' attribute in that object.

        Just one thing, it looks like around [qw[eyes ears nose mouth]] won't work. It should be just a straight array such as:  around qw[eyes ears nose mouth

        Sorry, yes that is correct I don't use the feature as often as the has [] one so I mix it up.

        I'd still don't get the subtleties of using handles against using MooseX::CurriedHandles --something I'll look into carefully soon.

        MooseX::CurriedHandles was originally called MooseX::DeepAccessor but it was expanded and renamed. It is an extension to handles which allows you go even deeper down the method chain if you like. The docs are pretty good, especially the INTERFACE section, however it very much helps to understand vanilla handles first.

        RE: MooseX::NestedPackage

        This looks interesting, but I am not sure it gives you all that much more over writing the packages yourself. I am of the opinion that optimizing for less typing is not really a large benefit. This is not to say that all languages should be as verbose as Java or C#, but that for real-world code it is not a true savings over the long term as it almost always needs to be un-golfed in the end. But that is simply my opinion, so take it with a big giant hunk of salt. You might want to take this to the mailing list (moose@perl.org) and see if anyone else has tried this or would be interested in it.

        -stvn

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://737145]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (3)
As of 2024-04-26 00:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found