Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Are lvalue methods (as properties) a good idea?

by jplindstrom (Monsignor)
on Jan 12, 2005 at 21:15 UTC ( [id://421777]=perlquestion: print w/replies, xml ) Need Help??

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

I found OOTools on cpanratings and became curious about how it provides a way to use object properties in a nifty way. This is example usage from the pod:

$object->digits = '123';

Looks nice and clean, enough for me to start using it.

But I think I remember that lvalue subs are considered experimental. I super searched here, but didn't become much wiser.

If I would start using this kind of syntax with this or some other module, are there any gotchas I should know about? Is anyone using lvalue methods/properties on a regular basis?

Or should I just stay away?

/J

Replies are listed 'Best First'.
Re: Are lvalue methods (as properties) a good idea?
by Zaxo (Archbishop) on Jan 12, 2005 at 22:08 UTC

    They're at their best when used with lexical closures. They make a very nice way to get subroutine-style scoping for class variables. That means they replace package globals with a slightly different scoping model. They have the advantage of being overridable and inheritable.

    Lexical closures on lvalue subs are less handy for object methods. You need to define the sub in the constructor and keep a reference to it around. It looks like that is what the package you mention probably does. Used as an lvalue, a naive instance method finds it tricky to associate itself with the correct object, and if the instance method didn't see the object data's my call when defined, trouble can result.

    I think that lvalue subs are stable to use for scalars. Afaik there are problems with list context for arrays and hashes. A fix for those is likely to break something.

    Lvalue subs are tremendous fun to experiment on. Here's an example whose effects are enlightening to investigate,

    my @crefs = do { my $foo = \$_; ( sub :lvalue { $$foo }, sub :lvalue { $foo } ) };

    After Compline,
    Zaxo

Re: Are lvalue methods (as properties) a good idea?
by Ovid (Cardinal) on Jan 12, 2005 at 21:42 UTC

    I'm not too fond of them. Currently, there is no clean way to validate the value:

    $object->digits = [qw/finger finger thumb/]; # whoops!

    One can use Attribute::Property for that, but then you're relying on a attributes and those rely on CHECK blocks and CHECK blocks don't run under all environments (mod_perl, for example). So if you want to use lvalues, feel free, but just be leery of using them in code that you distribute to others as they are rather fragile.

    Cheers,
    Ovid

    New address of my CGI Course.

      It's relatively clean to make the sub a closure on a tied scalar, where the STORE() method does the checking. That succeeds in highjacking assignment.

      I gave an example in To Validate Data In Lvalue Subs. That still seems to me like a clean and flexible approach to validation. As mentioned in that thread, Attribute::Properties uses this technique under the hood, but as you say the tie-in to an attributes interface reduces its applicability.

      After Compline,
      Zaxo

        Wow. That's one heck of a lot of overhead to support syntactic sugar :) When you have to make the sub a closure and tie it to a custom class to provide validation for lvalue attributes, I'm at a loss to see how this is preferable to:

        sub bar { my ($self, $bar) = @_; croak "bar() requires a hashref" unless 'HASH' eq ref $bar; $self->{bar} = $bar; return $self; }

        Cheers,
        Ovid

        New address of my CGI Course.

        Class::Accessor::Lvalue also allows you to create them for a class and it has the nice feature that a call to $a->wibble = 5 gets translated to $a->set_wibble(5) so all your usual verification code is still callable (or you can choose to autogenerate a plain old setter with Class::Accessor).

        In my own code I use my own method maker module (not on CPAN because there are already enough method makers on CPAN) that does something similar but slightly unusual. Doing

        package Foo; use Fergal::MM qw( Bar );
        will create a setBar and getBar pair of methods and also a Bar lvalue method which just calls setBar and getBar. So far, so normal. What's unusual is that it puts the methods into Foo::Methods and makes Foo inherit from Foo::Methods so that if I want to have something special (validation etc) happen when a setter or getter is called. I just do
        package Foo; use Fergal::MM qw( Bar ); sub setBar { my $self = shift; my $value = shift; check($value); $self->SUPER::setBar($value); }
        Yes, there's plenty of overhead in this but usually it doen't make any difference to me.

        Another interesting thing I do with lvalue accessors is to add indexed accessors. So I can do something like

        $a->Grid(2, 3) = $player1; $a->Grid(7, 5) = $player2;
        this gets translated into
        $a->setGrid($player1, 2, 3); $a->setGrid($player2, 7, 5);
        so by writing the correct setters and getters, you can create attributes that act like multidimensional arrays or hashes and that are also overrideable by sub classes and can have validation etc.
Re: Are lvalue methods (as properties) a good idea?
by Anonymous Monk on Jan 12, 2005 at 21:37 UTC
    Getters/setters break encapsulation, so if you are never trying to do the equivalent of overriding = to call additional code, you might as well be saying $object->{digits}=123 for that matter... If the module allows overriding of property methods on a case by case basis, then good for it...

      I hear this quite a bit but I never see anyone provide concrete references that really explain why getters and setters are such a horrible thing. I would really love to see more information on this.

      Cheers,
      Ovid

      New address of my CGI Course.

        Nothing wrong with doing them if you think it all through. But blindly providing getters and setters for all your member variables means you've published your invidual attributes as a public interface for your object, which means that any new version of your object has to support at least that specific interface.

        Your public interface should be carefully considered. If some parts of that interface map into a simple setter or getter, fine, do it. But don't do it blindly.

        -- Randal L. Schwartz, Perl hacker
        Be sure to read my standard disclaimer if this is a reply.

        It's not the getters and setters that ar bad, but using them to upset Mr Demeter.

        See also: Re^4: Law of Demeter and Class::DBI

        IMHO the Law of Demeter isn't like the speed of light, but it's a pretty good heuristic for OO design.

        /J

        I never see anyone provide concrete references that really explain why getters and setters are such a horrible thing

        Yes, I dislike emotional words like horrible and evil; writers employ these words as attention grabbers. As merlyn explains nicely, they are not always horrible or evil ... but can be if used unwisely. As usual, there are tradeoffs involved and mindless slogans cannot replace sound judgement, experience and good taste.

        A couple of general references that discuss this are:

        Allen Holub JavaWorld article Why getters/setters are evil
        AccessorsAreEvil
        TellDontAsk

Definition of lvalue
by tphyahoo (Vicar) on Jan 13, 2005 at 10:43 UTC
    I didn't know what lvalues were when I read this post, so I did a little research and found:

    Definition of lvalue: A reference to a location, an expression which can appear as the destination of an assignment operator indicating where a value should be stored. For example, a variable or an array element are lvalues but the constant 42 and the expression i+1 are not.

    http://www.google.de/search?q=cache:h6MRIOsNjKwJ:www.hyperdictionary.com/computing/lvalue+lvalue&hl=de

    thomas.

      That's a somewhat confusing defintion of lvalue. A lvalue, quite literally, is something that can appear on the left hand side of an = operator -- that is, something that can be assigned to. In perl, that includes assignable variables (read: almost all variables), and calls to lvalue subroutines (including lvaluable builtins like substr, and user-defined subroutines with the :lvalue attribute). (The first half of that includes, of course, any expression that results in an assignable variable, such as $foo->{bar}{baz}{quux}[-1].) The 42 in 42=1; is a non-lvalue in a slot that needs an lvalue. Note that there are places that need an lvalue other then the right-hand-side of a = operator, such as all the *= operators, ++ and --, and some sub arguments, sometimes only in some situations. In general, if an operation is going to modify something, that something must be an lvalue -- which is another defintion of lvalue: "something that can be modified".


      Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

Re: Are lvalue methods (as properties) a good idea?
by perrin (Chancellor) on Jan 13, 2005 at 19:19 UTC
    There may not be a good technical reason to stay away, but they look different from all other forms of method calls in Perl, which will make your code confusing to most other Perl programmers. It may also get you in the habit of writing method calls this way and that could cause you to make mistakes when using DBI, LWP, etc. It just adds to the cognitive dissonance.
Re: Are lvalue methods (as properties) a good idea?
by fletcher_the_dog (Friar) on Jan 14, 2005 at 15:33 UTC
    My biggest problem with lvalue subs is that they break in the debugger. Subs are intercepted in the debugger by a sub called DB::sub that is not an lvalue sub. So you get weird bugs when a program with lvalue subs that normally works fine is run through a the perl debugger, because values stop getting assigned in the lvalue subs

      This is fixed since 5.10.1.

Re: Are lvalue methods (as properties) a good idea?
by blazar (Canon) on Jan 14, 2005 at 16:25 UTC
    But I think I remember that lvalue subs are considered experimental. I super searched here, but didn't become much wiser.
    I think lvalue subs have been deemed experimental for quite a long time, but they've been there and working for all this time. As far as your question is concerned: most times you don't really need them, but in a few cases they provide what indeed seems to be the most natural and straightforward syntax for certain tasks. So it's indeed a nice feature to have. granted, it would be better if that "experimental" tag could be eliminated...

    PS: at least as of 5.8.6 the "experimental" mark is still there, see 'perldoc perlsub'.

      They will not be marked "experimental" in Perl 6. At least, no more experimental than Perl 6 itself...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://421777]
Approved by Old_Gray_Bear
Front-paged by bart
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (6)
As of 2024-04-18 14:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found