stevan / p5-mop-redux

A(nother) MOP for Perl 5
139 stars 36 forks source link

trait -> rw accessors return $self when used as setter #134

Closed forwardever closed 10 years ago

forwardever commented 10 years ago

is there a trait that makes rw accessors return $self when used as setter, so it is possible to chain

stevan commented 10 years ago

No, but it would be pretty easy to implement one.

sub chained_writer {
    my ($attr) = @_;

    die "rw trait is only valid on attributes"
        unless $attr->isa('mop::attribute');

    my $meta = $attr->associated_meta;
    $meta->add_method(
        $meta->method_class->new(
            name => $attr->key_name,
            body => sub {
                my $self = shift;
                $attr->store_data_in_slot_for($self, shift) if @_;
                $self;
            }
        )
    );
}
forwardever commented 10 years ago

thank you, will try

forwardever commented 10 years ago

okay, get My::Module=SCALAR(0x29f1280) instead of the actual value (getter)

stevan commented 10 years ago

ah, yes, sorry, you will need to do this:

sub chained_writer {
    my ($attr) = @_;

    die "rw trait is only valid on attributes"
        unless $attr->isa('mop::attribute');

    my $meta = $attr->associated_meta;
    $meta->add_method(
        $meta->method_class->new(
            name => $attr->key_name,
            body => sub {
                my $self = shift;
                if (@_) {
                    $attr->store_data_in_slot_for($self, shift);
                    return $self;
                } else {
                    return $attr->fetch_data_in_slot_for($self);
                }
            }
        )
    );
}
forwardever commented 10 years ago

works, thank you, are there docs or tests where I can find out how to get this into my mop implementation (do not want to write it as a sub in my main package)

maybe, this should be implemented in core, the mojolicious guys are making heavy use of it (e.g.)

stevan commented 10 years ago

Sorry, no docs yet.

Basically I suggest making a "MyProject::Traits" package and exporting it from there, this will allow you to control its usage.

I am not sure this is core-worthy, we are trying to keep things to a minimum.

forwardever commented 10 years ago

@stevan why are setters returning the value you set (as in Moose)

it is very hard to find a good reason for this behaviour, returning $self at least allows chaining

most of the time, the value I set is saved in a variable anyway, so return values are useless (I only make use of them in custom setters that do more crazy stuff)

forwardever commented 10 years ago

seems like we discussed this some time ago http://blogs.perl.org/users/forward_ever/2011/10/chaining-in-moose-mouse-moo-and-mo.html

stevan commented 10 years ago

Haha, yes we did :)

forwardever commented 10 years ago

your main argument those days was Moose compatibility

I can also live with personal custom traits (as shown by you above), but still think chaining is the predominant use case (and it would be faster if implemented as default ???)

will leave this issue open in case anybody wants to provide further thoughts, and close later if nobody cares :)

stevan commented 10 years ago

I disagree that chaining is the predominant use case. The standard perl accessor pattern that has been around for many, many years is to return the value that was just set. This is also a common pattern in a number of other languages I have used as well.

The only places where I have seen chaining (on a single instance) be the predominant pattern is jQuery and more recently Java (specifically some of the *Builder APIs that have come out recently).

forwardever commented 10 years ago

okay, I mean use cases in applications, not in the languages themselves, probably have seen too few apps that make good use of accessors returning the value that was just set

(with accessor, I mean simple ones, not the "crazy" ones you can create e.g. with moose)

doy commented 10 years ago

I don't think we're going to do this in core.