in reply to Re: Method Chaining and Accessors
in thread Method Chaining and Accessors

TheDamian suggests the use of get_foo and set_foo.This is because you have some attributes for which there will be a get_foo but no set_foo so the example was that a foo sub that is both a getter and setter has no way to indicate that you can not actually set foo, because if it dies then you have to wrap all your get/setters in eval { ... } and nobody wants that.

A good point, but I think you can make the case even more simply: undef is a useful value, and sometimes you want to set something to undef. If you use undef to indicate you want to do a get rather than a set, then you're stuck. So yeah, explicit getters & setters are good, and mutators aren't worth the saving of a few lines of code.

Myself, I'm inclined to name my setters "set_*" but to avoid using the prefix "get_" on my getters. I think that reads a little more naturally and helps to distinguish between the two:

my $attribute = $self->attribute; $self->set_attribute( $attribute );

Replies are listed 'Best First'.
Re^3: Method Chaining and Accessors
by f00li5h (Chaplain) on Apr 06, 2007 at 02:36 UTC

    Myself, I'm inclined to name my setters "set_*" but to avoid using the prefix "get_" on my getters

    But then your getters look exactly like the mutators you're trying to avoid! infact, your getters have exactly the same surprise toy inside!

    my $foo = Foo::Doom->new(); $foo->bar( 'shoe' ); # OH NOES! its just a getter # but it still looks right -_- # whereas my $f00 = Foo::f00li5h->new( in_accordance_with => TheDamian ); $f00->get_bar( 'shoe' ); # what the hell is 'shoe' there for? # this is clearly a getter

    Sure if you've got a bundle of other setters called, as set_foo in exactly the same place that you're adding the new code to set bar, you're a little less likely to write $foo->bar('shoe'), but only a litte.

    Personaly, I'd expect $foo->bar to be a mutator.

    @_=qw; ask f00li5h to appear and remain for a moment of pretend better than a lifetime;;s;;@_[map hex,split'',B204316D8C2A4516DE];;y/05/os/&print;
      But then your getters look exactly like the mutators you're trying to avoid!

      Not if you don't have any mutators, they don't.

      And since mutators are now deprecated, I don't see any point in letting them have the cleaner syntax.

      If I were working with a group of people I needed to ween away from mutators, I might have my getters warn if @_ isn't empty.

      if (@_) { carp "attempt to pass values to a getter"; }

      There's another issue with my naming convention, though:

      $attribute = $self->attribute; $attribute = $self->{attribute};
      With hash-ref based objects, cheating and peeking at the hash value looks an awful lot like using the getter correctly (or course, there'd be the same problem if it were a mutator). It could be argued that this would be more visually distinct:
      $attribute = $self->get_attribute; $attribute = $self->{attribute};

      Myself, I think what's needed is some sort of test code that looks for code that cheats and uses the object like a hash ref, but that's a project I keep putting off.

      (And personally, I'm holding off on "inside out objects" for now. I halfway expect that in a few years Damien Conway will announce that his "Class::Std" module is now deprecated, just like a lot of stuff in his "Object Oriented Perl" is now supposed to be deprecated, e.g. mutators.)

        I suggest that your carping still counts as a surprise and Personally, I think that get_foo is the cleaner of the two, but whatever floats your boat (or the boat of the person that writes your coding standards)

        Since $self->{attribute} is wrong it should look wrong. If it doesn't stand out as being, people may not spot it, or worse still, end up "fixing" the $self->get_attribute;

        And as for "Not if you don't have any mutators, they don't.". It gets a little tricky when you use someone else's cpan module that still uses mutators? *bam* you've got your getters, and their mutators, and there's arms legs and butts in all sorts of disorder!

        As an interesting development, kyle has just the thing to allow you to port to an insideout object system at Make an inside-out object look hash-based using overload.

        @_=qw; ask f00li5h to appear and remain for a moment of pretend better than a lifetime;;s;;@_[map hex,split'',B204316D8C2A4516DE];;y/05/os/&print;
Re^3: Method Chaining and Accessors
by TGI (Parson) on Apr 06, 2007 at 20:36 UTC

    Here's an accessor/mutator that is set up for chaining and will accept undef as a value.

    sub foo { my $self = shift; # Set attribute if any args if ( @_ ) { $self->{foo} = shift; #validation is for chumps return $self; } else { return $self->{foo} } die "Whiskey Tango Foxtrot"; } # cotrast with this version, which I think you had in mind sub undefoo { my $self = shift; my $newfoo = shift; if ( defined $newfoo ) { $self->{foo} = $newfoo; # What, me validate input? return $self; } else { return $self->{foo}; } die "Whiskey Tango Foxtrot"; }
    print $obj->foo(undef), "\n"; # Prints object stringification print $obj->undefoo(undef), "\n"; # prints a "\n"

    I don't know how I feel about chaining mutators. I like accessor/mutators that always return the attribute value.


    TGI says moo