jdhedden has asked for the wisdom of the Perl Monks concerning the following question:

It seems that there are several different takes on what a set-type method should return to indicate success:
  1. Return the previous value (or undef if none). Rationale: Saves performing a 'get' prior to the 'set' in case you need to restore the previous value.
  2. Return the value being set. Rationale: Allows you to check that it got set correctly.
  3. Return the object itself. Rationale: Allows you to chain methods together: $obj->set_xxx($value)->do_something_else()
I wrote Object::InsideOut to do #2, but my rationale at the time wasn't strong.

Is there a concensus as to which of the three is 'best'?


Remember: There's always one more bug.

Replies are listed 'Best First'.
Re: 'Set' Method Return Value
by ikegami (Patriarch) on Nov 22, 2005 at 19:27 UTC
    1. Nothing to add but an example: select FH uses this, since one often wants to re-select the originally selected file handle.

    2. I don't buy the rationale you gave for this method. The caller should not have to do integrity checks. The rationale for this one is probably for consistency with $b = $a = $val.

      This method is also useful when you want to provide a single method for setting and getting. For example, $cypher->iv($iv); and $iv = $cypher->iv();.

    3. This method can improve readability. A common alternative is a constructor that accepts a list (or a reference to a hash) of options.

    However, I beg to differ on their ability to indicate success. None of these are particulary good at indicating success, because none of these are particulary good at indicating failure.
    1. Without limiting the values that can be used as parameters, the return value cannot be used to indicate failure. Some other means of indicating failure (such as exceptions) is necessary.

    2. Checking for failure entails check checking if the return value is different than the parameter's value. This could entail having to use a temporary variable, and checking if two things are equal can be very tricky depending on what kind of things make accesptable parameter. In short, some other means of indicating success (such as exceptions) would be preferable.

    3. In this case, a false value could be returned on failure, but that would cancel out the entire benefit of this method. If the function can return undef, one can no longer chain calls, since one would have to check the return value. It would be safer to just return 1 for success and undef for failure.

Re: 'Set' Method Return Value
by Limbic~Region (Chancellor) on Nov 22, 2005 at 19:24 UTC
    jdhedden,
    Option 2 has another thing going for it besides verification - consistency. A 'Set' method is equivalent to assignment with the = operator in Perl. Unless you want to document why you are deviating from that consistency and violating the principal of least suprise - it makes sense to go with option 2.

    You can use things like wantarray and Want to try and figure out the context of the method call to be smart about the return value allowing more behavior. I prefer the KISS method over smart approaches most of the time.

    Whatever you decide - document, document, document!

    Cheers - L~R

Re: 'Set' Method Return Value
by blue_cowdawg (Monsignor) on Nov 22, 2005 at 19:50 UTC
        1. Return the previous value (or undef if none). Rationale: Saves performing a 'get' prior to the 'set' in case you need to restore the previous value.
        2. Return the value being set. Rationale: Allows you to check that it got set correctly.
        3. Return the object itself. Rationale: Allows you to chain methods together: $obj->set_xxx($value)->do_something_else()

    I know in the Java world there are distinct getters and setters and they seem to follow a fourth path that you didn't list where setters are void and getters return the value.

    In writing objects in Perl I've always followed the pattern of having the getter and setter be the same routing where I test for a passed in value and if it exists I set the member field to that value. No matter what if there was a passed value or not I still return the value contained in that member field. In the case of where a value was passed in I return the newly set value.

    # # Getter Setter for member field foo sub foo { my $self = shift; if ( defined $_[0] ) { $self->{foo} = $_[0]; } return $self->{foo}; }
    Which is the best way? I think your milage varies and it all depends on personal preference or the architecture you are building against.


    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
Re: 'Set' Method Return Value
by dragonchild (Archbishop) on Nov 22, 2005 at 20:16 UTC
    In Ruby, the default setter is a lvalue-able form of the getter and is defined with the name "foo=()". They are generally named after the attribute. So, attribute foo would have a getter of val = obj.foo and a setter of obj.foo = newval. You can do val2 = obj.foo = newval and both val2 and obj.foo have newval as a value. So, Ruby would follow #2.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: 'Set' Method Return Value
by phaylon (Curate) on Nov 22, 2005 at 19:56 UTC
    Is there a reason this couldn't be decidable by the author of the object using O::IO?

    Ordinary morality is for ordinary people. -- Aleister Crowley
      Yes, I am contemplating just that.

      Update:
      I have released Object::InsideOut v1.14 that allows the developer to specify the return value for set-type accessors. The default being the value being set.

        Well, when I have doubts about a decision, I usually take the road that gives more freedom ;)

        Ordinary morality is for ordinary people. -- Aleister Crowley
Re: 'Set' Method Return Value
by Roy Johnson (Monsignor) on Nov 22, 2005 at 19:48 UTC
    If you've got a member that can be set and got, do away with (or hide via tie) the accessor methods and just let the user directly access the member.

    If it's a set-only value, return the object.


    Caution: Contents may have been coded under pressure.
      Roy Johnson,
      You asked in the CB what was wrong with this node. I am replying here for the benefit of everyone - not just those present in the CB at the time. It sounds like you are recommending breaking encapsulation. This may not be the case, but when you say "just let the user directly access the member", it implies $obj->{member} which would break if the underlying object were later turned into an array for instance.

      I am not saying your node is wrong, I am saying I can see why people might think that. If this isn't what you are suggesting, perhaps you should provide something a bit more clear.

      Cheers - L~R