Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re: tie'ing a scalar as an array?

by ruoso (Curate)
on Jul 18, 2006 at 20:19 UTC ( [id://562119]=note: print w/replies, xml ) Need Help??


in reply to tie'ing a scalar as an array?

Looks a little weird, but, doesn't this solve your problem?

use strict; use warnings; package Foo::Bar; sub new { tie my @arr, 'Foo::Bar'; return bless \@arr, 'Foo::Bar'; } sub lalala { my $self = shift; print "Lalala\n"; } sub TIEARRAY { return bless [], 'Foo::Bar'; } sub FETCH { print "Fetch\n"; my ($self, $index) = @_; return $self->[$index]; } sub STORE { print "Store\n"; my ($self, $index, $value) = @_; return $self->[$index] = $value; } package main; my $a = Foo::Bar->new(); $a->lalala(); $a->[0] = 1; print $a->[0];
daniel

Replies are listed 'Best First'.
Re^2: tie'ing a scalar as an array?
by rvosa (Curate) on Jul 19, 2006 at 06:42 UTC
    I'm afraid I still don't quite understand the relationship between \@arr in the constructor and the [] array ref in TIEARRAY. Would you mind rewriting this example in a way that demonstrates the "two-faced" aspect of what I'm trying to achieve? There is something like it in perltie, but it doesn't actually have an additional 'new' constructor to abstract away the tie'ing (and uses a hash) and I couldn't quite rework it in the way I intend.

    Thanks so much!

      Ok, Here goes a more complex example, wich shows it in more details:

      use strict; use warnings; package Foo::Bar; sub new { tie my @arr, 'Foo::Bar'; return bless \@arr, 'Foo::Bar'; } sub TIEARRAY { my $scalar = "A Scalar"; return bless \$scalar, 'Foo::Bar'; } sub FETCH { my ($self, $index) = @_; print 'FETCH '; if ($index == 0) { return $self->lalala0; } elsif ($index == 1) { return $self->lalala1; } else { return undef; } } sub STORE { my ($self, $index, $value) = @_; print 'STORE '; if ($index == 0) { return $self->lalala0($value); } elsif ($index == 1) { return $self->lalala1($value); } else { return undef; } } sub lalala { my $self = shift; if (UNIVERSAL::isa($self,'ARRAY')) { $self = tied(@{$self}) }; print "Lalala $self\n"; } sub lalala0 { my $self = shift; if (UNIVERSAL::isa($self,'ARRAY')) { $self = tied(@{$self}) }; print "Lalala0 $self\n"; } sub lalala1 { my $self = shift; if (UNIVERSAL::isa($self,'ARRAY')) { $self = tied(@{$self}) }; print "Lalala1 $self\n"; } sub DESTROY { my $self = shift; if (UNIVERSAL::isa($self,'ARRAY')) { print "Destroying the array...\n"; } else { print "Destroying the scalar...\n"; } } package main; my $a = Foo::Bar->new(); # The object inside is a SCALAR $a->lalala(); $a->[0] = $a->[1]; $a->[1] = $a->[0];

      UPDATE: Included the DESTROY method, to illustrate...

      daniel
        Thanks, that's cool!

        Do I understand correctly that the lowercase methods can either be invoked on the scalar or the array (as both are blessed into the package), and therefore you sometimes have to retrieve the tied scalar from the array (if that happens to be the invocant)?

        So, if you use, say, a $a->[0] construct, the STORE method is called on the array reference. STORE then invokes $a->lalala0 on the array, so the lalalao sub needs to retrieve the tied scalar from the invocant array.

        Is that sort of how it works?
Re^2: tie'ing a scalar as an array?
by rvosa (Curate) on Jul 18, 2006 at 20:43 UTC
    Thank you both for your replies. Unfortunately, they don't completely address my question. The big idea was that the objects themselves would still be scalar references (not array references), except they would behave as array references. In the perltie perldoc there is an example that does this with a hash reference, so I think it must be possible.

    In the original class constructor a UID is generated. The object is a reference to this UID (hence a scalar). I like to keep this (but have the objects behave as array references).

      You still have tied($arr_ref) to get your scalar reference

      daniel
        Indeed I do. Mmmmm, I can work with that. Thanks!
        This more or less does the trick:
        package TwoFaced; use strict; my $instance_counter = 0; my $instance_array = []; sub new { my $class = shift; my @array; tie @array, $class, @_; return bless \@array, $class; } sub method { print "Method call\n"; return; } sub TIEARRAY { my ( $class, @args ) = @_; my $self = $instance_counter++; return bless \$self, $class; } sub FETCH { my ( $self, $i ) = @_; return $instance_array->[ $$self ]->[$i]; } sub STORE { my ( $self, $i, $val ) = @_; if ( not $val eq 'a' ) { $instance_array->[ $$self ]->[$i] = $val; return $self; } else { die "Illegal value: $val\n"; } } sub FETCHSIZE { my ( $self ) = @_; return scalar @{ $instance_array->[ $$self ] }; } sub DESTROY { print "Contents at death:\n"; print "\t", $_, "\n" for @{ $instance_array->[ $$_[0] ] }; } package main; my $t = new TwoFaced; print "it's an array!\n" if UNIVERSAL::isa($t, 'ARRAY'); # prints "it' +s an array!"; $t->[0] = 'b'; print ${ tied @$t }, $t->[0]; # prints "0b" print $t->method; # prints "Method call" $t->[0] = 'a'; # dies "Illegal value: a" # prints "Contents at death: ..." during object destruction
        ...except the destructor is called twice. I presume this is for the @array and the tied object respectively?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://562119]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (2)
As of 2024-04-19 01:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found