Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

bless + tie

by cbraga (Pilgrim)
on Oct 01, 2003 at 05:26 UTC ( [id://295518]=perlquestion: print w/replies, xml ) Need Help??

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

The problem: Getter and setter methods suck. Even if they're autogenerated, they still suck because we can't interpolate them inside a string.

Possible solution: Make the object act as a tied hash, which can be interpolated. When a property being set or got requires special processing do it, otherwise just set/get the value in the ordinary, blessed object hash ref. Let ordinary methods work as usual.

Has anybody tried this yet? Can it even be done? What pitfalls might lie in the way?

Replies are listed 'Best First'.
Re: bless + tie
by blokhead (Monsignor) on Oct 01, 2003 at 05:52 UTC
    In my opinion, you lose some expressiveness by going entirely to tied objects. If your objects are more than just structs, you will have some method calls like this:
    my $ret = $obj->do_something($with, $these, $args);
    The only (sane) way to do this with the tied approach is using tied(%h), which I think is really ugly.

    One thing you might consider (which I've never tried) is to overload the hashref operator for your objects. The perldoc for overload has some examples about overloading these referencing operators. Something like this:

    package Widget; use overload '%{}' => sub { my $self = shift; tie my %h, __PACKAGE__, $self; \%h; };
    Create a hash tie'd into the same package, that has an associated object. Then have FETCH (and STORE if you like) just translate into the appropriate method calls on that object, of course ignoring keys that aren't for just getter/setter methods. Then you could interpolate like this:
    my $widg = Widget->new; print "$widg->{name} is the same as " . $widg->name;
    Note that this will work even if you don't implement your class using blessed hashrefs. And you still can protect the object's internals from direct access..

    Update: Now that I think of it, could TIEHASH in this class be implemented like this (i.e, the tied hash is the object it it corresponds to)?

    sub TIEHASH { my ($pkg, $object) = @_; return $object; } sub FETCH { my ($self, $key) = @_; $self->$key; }
    Like I said, I've never tried this so I could be missing something, but it sounds like fun. ;)

    Update 2: It's almost a day later and I just thought of something. If anyone is coming to this thread late, I just want to warn you that your '%{}' overload needs to still allow for the class methods to get to the "real" internal data structure (only if your real structure is a hashref of course)! You will probably have to have to use caller to sort out which times the hashref overload must actually return the real object.

    blokhead

      That's exactly what I wanted to do. I'll be sure to try them. Thanks.
Re: bless + tie
by tachyon (Chancellor) on Oct 01, 2003 at 05:58 UTC

    This rather defeats the point of OO arch. Presumbably you want to do this:

    $obj->{attibute} # instead of $obj->get_attribute();

    Which given that most object are just blessed hashes you can do right now.....

    package Foo; use Data::Dumper; my $o = new Bar; print $o->get_attribute(), $/; print $o->set_attribute('new val'), $/; print $o->set_flubber('dubber'), $/; print "Direct access, interpolated get flubber = $o->{flubber}\n"; print $o->no_exist(); print Dumper $o; package Bar; sub new{ return bless { attribute => 'value' }, shift } sub AUTOLOAD { my $self = shift; my ( $func ) = $AUTOLOAD =~ m/::([^:]+)$/; if ( $func =~ s/^set_// ) { return $self->{$func} = shift; } elsif ( $func =~ s/^get_// ) { return exists $self->{$func} ? $self->{$func} : undef; } else { my @caller = caller(); warn "Non existant function $func() called by:\n@caller\n"; return 0; } } sub DESTROY{}

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      I wanted to get rid of getter/setter methods (even those generated by autoload) replacing them with hash access, while preserving object integrity by intercepting the hash accesses and possibly processing them in a tied hash fashion...

        My point would be what on earth for. Just so you can do this:

        print "Blah $obj->{attribute} blah\n"; # instead of print "Blah ", $obj->get_attribute(), " blah\n";

        Seems to me all you achieve is to obfuscate your code, make it less maintainable, and slow it down.....

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: bless + tie
by dws (Chancellor) on Oct 01, 2003 at 06:14 UTC
    Even if they're autogenerated, [getter and setter methods] still suck because we can't interpolate them inside a string.

    Can you expand on why this is a problem for you? In particular, why do you find code like

    "foo's bar is " . $foo->getBar() . "!"
    to be a problem worth throwing tied variables at?

      First, it's more trouble to type and I also think its ugly as hell. Heck, if I liked that sort of code I'd be programming in VBScript.
        First, it's more trouble to type and I also think its ugly as hell.

        So to save a few keystrokes and indulge your aesthetic sense, you're prepared to use tied variables? I rather think that, on balance, you're losing ground.

Re: bless + tie
by demerphq (Chancellor) on Oct 02, 2003 at 12:18 UTC

    Getter and setter methods suck.

    Who write getter and setter methods in Perl? Oh right, those guys from languages with less flexible OO models...

    sub property { my $self=shift; if (@_) { $self->{property}=shift; return $self; } else { return $self->{property}; } }

    Even if they're autogenerated, they still suck because we can't interpolate them inside a string.

    print "Property: @{[$obj->property]}\n";

    Course it is one char more than using stright concatenation.

    If you do go the tie overload route (not _such_ a bizarre course, but one I think ultimately youll reject as a Neat Idea But....), then you should carefully read the example code at the bottom of the overload documentation. It contains a full implementation of a two face tie. The trick is that for it to work you need to keep your underlying object representation at least one step away from the one you plan to expose. For instance your object could be a reference to a reference to a hash. Then you could overload the hash dereference or array dereference as you choose. Of course this will slow your program down and it will introduce nasty horrible bugs in various versions of perl that will make the tricks dangerous enough that I doubt its worth your while. *shrug*.

    In case its not clear, I'm _fully_ with tachyon on this one.


    ---
    demerphq

      First they ignore you, then they laugh at you, then they fight you, then you win.
      -- Gandhi


Re: bless + tie
by Anonymous Monk on Oct 02, 2003 at 19:24 UTC

    Actually, you can interpolate calls to getter methods inside a string. Consider the below:

    "this is the result: ${\$obj->get_whatever}"

    Slightly strange syntax, but it works fine for any Perl expression that evaluates to a scalar (though you'll need to put non-trivial expressions in parenthesis).

Re: bless + tie
by tilly (Archbishop) on Oct 05, 2003 at 02:59 UTC
    What you ask for is easy to implement. But rather than do that, I would like to question the assumptions behind the problem that you are asking.

    For many problem contexts, having myriads of get/set methods lends itself to bad designs. It may be better to come up with better designs rather than trying to make a fundamentally bad design more convenient to work with.

    For more on this see this Java article. I don't agree with all of it (I think that he is too quick to discount some alternate strategies), but I agree with enough of it to recommend it as an eye-opening prescription for assumptions that many make for how they should organize affairs.

    There is nothing so hard to get around as the assumption that you don't even know that you are making...

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-04-25 11:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found