http://qs321.pair.com?node_id=390896

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

I was wondering if there is any way built-in to Class::Struct generated objects that would allow incrementing (and decrementing) in an overloaded sort of way, as opposed to building my own operator overloads. What i mean is, i'd like to be able to do something like:
use strict; use warnings; use Class::Struct; struct MyStruct => { 'Counter' => '$', ... } my $x = MyStruct('Counter', 0); $x->Counter++; # of course i could always do the following: $x->Counter( $x->Counter + 1 );
Is what i want to do directly possible (built-in)? I suppose i'd also like to be able to:
... $x->Counter += 7;
will i need to build my own overloads?

Replies are listed 'Best First'.
Re: Class::Struct question
by ikegami (Patriarch) on Sep 14, 2004 at 18:17 UTC

    On the plus side, it's possible, and you don't even need overloaded operators.

    use strict; use warnings; package MyStruct; sub new { my $class = shift(@_); return bless({@_}, $class); } sub Counter : lvalue { my $self = shift(@_); $self->{'Counter'} = $_[0] if (scalar(@_)); $self->{'Counter'} } package main; { my $x = MyStruct->new(Counter=>0); print($x->Counter, "\n"); # 0 $x->Counter($x->Counter + 1); print($x->Counter, "\n"); # 1 $x->Counter = $x->Counter + 1; print($x->Counter, "\n"); # 2 ++($x->Counter); print($x->Counter, "\n"); # 3 ++$x->Counter; print($x->Counter, "\n"); # 4 $x->Counter++; print($x->Counter, "\n"); # 5 $x->Counter += 1; print($x->Counter, "\n"); # 6 }

    On the downside, you can't use Class::Struct with this method, or you have modify it slightly. I think the changes are limited to the following:

    Change (untested)
    $out .= "  sub $name {$cmt\n    my \$r = shift;\n";
    to
    $out .= "  sub $name : lvalue {$cmt\n    my \$r = shift;\n";
    and scalar accessors will be returned by lvalue. Array accessors and hash accessors need a little more changes, because they use 'return' than that wipes the lvalue-ness.

Re: Class::Struct question
by hardburn (Abbot) on Sep 14, 2004 at 16:36 UTC

    No, but for reasons that have nothing to do with Class::Struct, and everything about Perl OO and operator precedence. Since '++' binds more tightly than '->', when you say:

    $x->Counter++;

    According to B::Deparse, Perl translates that to:

    ++$x->Counter;

    Which should then be tokenized into something like:

    (++$x) -> Counter

    Which is probably not at all what you want.

    Without knowing your specific situation, I would suggest looking more carefully at your object structure. What you're trying to do indicates to me that you're playing too closely to the object's internals.

    Update: Forget I said anything. See ikegami's response below.

    "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

      ++' binds more tightly than '->'

      That's not true. '->' is just above '++' in precedence. ++$x->Counter; is the same as ++($x->Counter);. The problem is that Counter does not return an lvalue. See the other post I'm making in this thread for an example.