http://qs1969.pair.com?node_id=219532


in reply to Re^3: Tutorial: Introduction to Object-Oriented Programming
in thread Tutorial: Introduction to Object-Oriented Programming

Another issue has just come to mind. With the object attributes being keyed on "$self", which includes the name of the class, you can no longer bless an object into a sibling class to implement state transitions.

Again, I guess some people would consider this a feature. I quite like the technique myself :-)

To overcome you'll need to strip out the class name. Assuming nobody changes the output format of references in later perl versions something like this should work.

package Foo; use strict; use warnings; use overload; my %foo = (); my %self = (); # we access self enough for it to be worth caching sub self { my $self = overload::StrVal shift; return $self{$self} if exists $self{$self}; $self{$self} = substr($self, index($self, '=')+1); }; sub new { my $class = shift; bless [], $class; }; sub foo { my $self = shift->self; $foo{$self} = @_ if @_; $foo{$self}; }; sub DESTROY { my $self = shift->self; delete $foo{$self}; undef %self; };

Also, there is another advantage to Abigail-II's method. Storing the attributes in separate hashes should less expensive in memory - buckets cost less than hashes. Might make a difference if you're creating lots of objects.

Replies are listed 'Best First'.
Re: Tutorial: Introduction to Object-Oriented Programming
by Abigail-II (Bishop) on Dec 13, 2002 at 11:02 UTC
    There's an easier way to strip out the class name. A reference in numeric context returns just the number part - so you could do my $self = 0 + shift;.

    Abigail

      Your right - forgotten about that.

      You still have the problem of overloading tho - what if a subclass overloads "+"?

      Unfortunately, there isn't an overload::NumVal to match overload::StrVal (unless I'm missing something somewhere ;-)

      You can get around this by blessing the object into another class you know isn't overloaded, get the numeric ID, and then bless the object back into it's original class. For example:

      package Foo::Base; use strict; use warnings; sub self { my $self = shift; my $package = ref($self); bless $self, __PACKAGE__; my $id = $self+0; bless $self, $package; return($id); }; package Foo; use base qw(Foo::Base); use strict; use warnings; my %foo = (); sub new { my $class = shift; bless [], $class; }; sub foo { my $self = shift->self; $foo{$self} = @_ if @_; $foo{$self}; }; sub DESTROY { my $self = shift->self; delete $foo{$self}; };

      Mildly evil - but seems to work.

        Unfortunately, there isn't an overload::NumVal to match overload::StrVal (unless I'm missing something somewhere ;-)

        I think the best way to do this is Scalar::Util::refaddr. And its much faster than parsing overload::StrVal.
        :-)

        But it isn't core (at 5.6 anyway)
        :-(

        --- demerphq
        my friends call me, usually because I'm late....