Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

tie'ing a scalar as an array?

by rvosa (Curate)
on Jul 18, 2006 at 08:30 UTC ( #561963=perlquestion: print w/replies, xml ) Need Help??

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

Dear monks,

I am trying to achieve the following functionality: I have an inside-out class where the underlying data structures of the objects are scalar references. I'd like to be able to access the contents referenced by objects from this class as arrays, i.e.:
use Foo::Bar; my $fb = Foo::Bar->new; $fb->[0] = 12; # here Foo::Bar::STORE($self,$index,$value) is called print $fb; # not sure, maybe Foo::Bar=SCALAR(0x1835bfc)?
Along similar lines, I'd like to be able to push @$fb, etc. (which would call the PUSH method). I have perused the documentation for perltie and overload and I think it must be some combination of that, but the best I could come up with was using:
use Foo::Bar; tie my @array, 'Foo::Bar'; $array[0] = 12; # here Foo::Bar::STORE($self,$index,$value) is called
...which is not really what I want. I want the constructor, data structure (scalar ref) and interface to remain the same, and just add syntax sugar. I'm guessing I have to call TIEARRAY in some way in the new constructor?

Thanks for any and all help!

Replies are listed 'Best First'.
Re: tie'ing a scalar as an array?
by Zaxo (Archbishop) on Jul 18, 2006 at 09:21 UTC

    Overloading won't be necessary. You can tie an array to your Foo::Bar object by defining the methods Foo::Bar::TIEARRAY(), Foo::Bar::FETCH, Foo::Bar::STORE(), etc. They will all look like ordinary instance methods except TIEARRAY(), which looks like a class constructor method.

    It's not difficult to write methods which tie an array to an array reference. The methods' arguments can be found in perltie. For example,

    # args: self, index, value sub STORE { my ($self, $index, $value) = @_; $self->[$index] = $value; }
    All the methods will be equally trivial. You'll need to define most all of the operator methods (POP(), PUSH(), SPLICE(), . . .) to get full array syntax.

    The tied operator returns the tied object, so you can call the Foo::Bar::baz() method on your array by,

    tied(@array)->baz();

    After Compline,
    Zaxo

Re: tie'ing a scalar as an array?
by ruoso (Curate) on Jul 18, 2006 at 20:19 UTC

    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
      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
      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
Re: tie'ing a scalar as an array? (use overload, not tie)
by ysth (Canon) on Jul 19, 2006 at 01:19 UTC
    overload can do this, tie can't (though it's possible to also tie the array whose reference you want your object to pretend to contain).
    package Foo::Bar; use strict; use warnings; my @aoa; my $cnt; sub new { bless \(my $obj_index = $cnt++) } sub DESTROY { undef $aoa[${$_[0]}] } use overload '@{}' => sub { $aoa[${$_[0]}] ||= [] }, fallback => 1; 1;

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (8)
As of 2021-01-21 18:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?