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

First, for some background, see Object and tied hash all at once? on the ability to make a scalar ref act as both a hash and an object. I'm looking for something similar with an array and an object, and while the basic setup seems ok, I'm running into problems when I'm trying to expand the functionality of the tied object.
The basic code I'm using is:
package Test; use Tie::Array; use Exporter(); @ISA = qw( Exporter Tie::StdArray ); sub new { my $class = shift; my @self; tie @self, $class; bless \@self, $class; } sub test { print "hello world\n"; } sub test2 { my $self = shift; print $self->{ test }, "\n"; # LINE 22 } sub TIEARRAY { my $class = shift; return bless { test => [] }, $class; } sub STORE { my $class = shift; my $index = shift; my $value = shift; $self->{ test }->[ $index ] = $value; } sub FETCH { my $class = shift; my $index = shift; return $self->{ test }->[ $index ]; } my $test = new Test(); $test->[0] = "test"; $test->test(); $test->test2();
Everything up to the second last line works, but when test2() is executed, I get "Can't coerce array into hash" at line 22 as indicated. Data::Dumping the $self value in the object functions shows what looks like a tied object, that is, an array and a class name. I've tried playing with tied, but with no luck.

I am looking to get to the interface to this class as in the code at the bottom of the file. Since I need to allow the user to use the array as a true array, I can't simply create a class and override []. I need to have added data storage in this case for extra varibles that can be set. I believe that a possible workaround would be to store a hashref in the last element of the tied array, and use the various tie functions to avoid the user from accessing this while having them available to the class, but this seems hack-ish.

Any suggestions on where to go from this?

-----------------------------------------------------
Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
"I can see my house from here!"
It's not what you know, but knowing how to find it if you don't know that's important

Replies are listed 'Best First'.
Re (tilly) 1: Combined tied-array / object problem
by tilly (Archbishop) on Nov 11, 2001 at 07:14 UTC
    sub test2 { my $self = shift; print tied(@$self)->{ test }, "\n"; # LINE 22 }
    BTW a recommendation. It is tempting to think in terms of "This class is X. My object is in the class. Anything I tie is tied to X." This is a trap. You will quickly find great confusion arising from the fact that sometimes you are getting a tied thing, and sometimes you are getting the object behind the tie. Therefore I recommend that you have two classes. One for the object, and a different one to tie it to.
      I would strongly second tilly's recommendation, and not merely so as to avoid confusion.

      There are also bugs in some versions of perl that cause objects that are blessed and tied to the same class not to behave correctly. In some versions destructors are not called consistently on such objects; in others, operator overloading of tied-and-blessed objects is broken.

      The problems seem to vary both from version to version, and from platform to platform. So even if your particular usage works on your particular version of perl on your particular machine, it's unlikely to be temporally or spatially portable.

      I ran into this problem when I was writing Regexp::Common, and quickly decided that the three extra lines needed to implement separate tieable and blessable classes were a very small price to pay to retain my sanity. ;-)

Re: Combined tied-array / object problem
by Aristotle (Chancellor) on Nov 11, 2001 at 07:44 UTC
    I suggest you set it up as a regular tied array. Users will then have to use tied(@array)->special_method(), but that little bit of extra code buys you so much clarity.
Re: Combined tied-array / object problem
by chipmunk (Parson) on Nov 11, 2001 at 21:30 UTC
    I note that, in your STORE and FETCH functions, you shift the first argument into $class, then operate on the undeclared $self. strict would have caught this error.

    Of course, fixing that will still leave you with the more insidious problem that tilly pointed out.