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


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

Abigail-II will be better able to comment than myself, but I've been playing around with her technique on-and-off since I discovered it on perlmonks. While I've not been doing it in anger, it's not been entirely in jest either. I've been re-writing some Test::Class hierarchies that were fairly deep, and hence possible sources for hash key clashes.

In general I've not had problems. It's a very nice hack to get around perl's lack of object attribute encapsulation. I'll probably use the technique in the next production project I do.

Abigail-II - have you considered writing a little tutorial on the subject? :-)

Issues that can cause problems:

Replies are listed 'Best First'.
Re^4: Tutorial: Introduction to Object-Oriented Programming
by adrianh (Chancellor) on Dec 13, 2002 at 08:32 UTC

    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.

      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.