Both Methods and Indexing for Objects?

Discussion in 'Perl Misc' started by Veli-Pekka Tätilä, Jul 31, 2007.

  1. Hi,
    I'd like to treat an object like an array but also provide methods for
    accessing bits of the object state that aren't array-like. An example in
    which this would be useful comes from Ruby, its regexp Match objects are
    indexable like arrays for accessing back references, yet they also have
    a nice interface via methods. Can Perl also do objects having both
    methods and hash or array-like indexing?

    I think I've found one possible solution, for arrays at least, after
    reading Object Oriented Perl Ch 9.7 on tied objects. You could have a
    constructor that returns a blessed ref to an underlying tied array,
    which the user accesses like any array ref. As it is tied, its easy to
    make the array read-only, for instance, if more restricted access is
    desired. As the object made by the constructor is a blessed scalar the
    user can also call methods on it. One way to handle the methods, and
    also be able to store object state beside the array itself, is to
    implement the tied array as a blessed hash behind the scenes. When a
    method in which the non-array bits of the object are needed gets
    called, you can dig up the underlying object behind the tied array via
    tied.

    To my surprise, at least in this simple script, both the array and the
    object usage seem to be working OK. On second thought, putting the
    methods dealing with tied variables in a separate package might have
    been cleaner.

    Are there easier ways of achieving essentially the same thing? Howabout
    modules that would factor out the common bits even further, so that you
    could state which hash member should have array-like access - in the
    spirit of how Struct and MethodMaker automate matters. I'm still a bit
    envious of Ruby's mixins and have been thinking of ways to implement
    them in Perl, too.

    And now the code, currently in a single file:

    package TiedArray;
    use strict; use warnings; use Tie::Array;
    our @ISA = qw|Tie::Array|;

    sub new
    { # Tie an array and bless the tied variable in $class.
    my $class = shift;
    my @array;
    tie @array, $class, @_;
    bless \@array, $class;
    } # sub

    sub TIEARRAY
    { # Implement as a hash with an array field.
    my $self = { };
    bless $self, shift;
    $self->init(@_);
    return $self;
    } # sub

    sub init
    { # Add fields and process arguments.
    my $self = shift;
    $self->{data} = shift;
    } # sub

    sub object
    { # Get the tied object given the tied variable $self.
    my $self = shift;
    tied @$self;
    } # sub

    # Pasted from Tie::StdArray with minor mods, as the array is in a hash.
    sub FETCHSIZE { scalar @{$_[0]{array}} }
    sub STORESIZE { $#{$_[0]{array}} = $_[1]-1 }
    sub STORE { $_[0]->{array}[$_[1]] = $_[2] }
    sub FETCH { $_[0]->{array}[$_[1]] }

    # Methods for the underlying object:
    sub data
    { # Accessor for the "data" hash member.
    my $self = object(shift);
    return $self->{data} unless @_;
    $self->{data} = shift;
    } # sub

    sub size
    { # Getting the array size as a method.
    my $self = shift;
    return scalar @$self;
    } # sub
    1;

    package main; # Some rather arbitrary tests.
    my $array = TiedArray->new('stuff');
    @$array[0 .. 1] = (qw|first second|);

    print "Array: @$array\n";
    print "Data: ", $array->data(), "\n";

    $array->data('foo'),
    push @$array, int(10 * rand) for 1 .. 4;

    print "Array: @$array\n";
    print "New data: ", $array->data(), "\n";

    @$array = splice @$array, 1, 2;
    print "Array: @$array\n";
    print $array->size(), " elements.\n";

    Thanks for any help in advance. I'm rather new to Perl OOP, especially
    tied variables.

    --
    With kind regards Veli-Pekka Tätilä ()
    Accessibility, game music, synthesizers and programming:
    http://www.student.oulu.fi/~vtatila
    Veli-Pekka Tätilä, Jul 31, 2007
    #1
    1. Advertising

  2. Veli-Pekka Tätilä

    -berlin.de Guest

    Veli-Pekka Tätilä <> wrote in comp.lang.perl.misc:
    > Hi,
    > I'd like to treat an object like an array but also provide methods for
    > accessing bits of the object state that aren't array-like. An example in
    > which this would be useful comes from Ruby, its regexp Match objects are
    > indexable like arrays for accessing back references, yet they also have
    > a nice interface via methods. Can Perl also do objects having both
    > methods and hash or array-like indexing?


    You can overload de-referencing in your class. That won't make objects
    look like arrays, but like array references, which may be good enough.

    I've made up a Regex class that behaves a bit like what you describe.
    After a match, an object can be used like an array ref that holds
    the captured strings (with the entire match in array position 0).

    Anno

    -----------------------------------------------------------------------

    my $r = Regex->new( '(.)(.)(.)');
    $r->match( 'abc');

    print "$r->[ $_]\n" for 1 .. 3;
    print "@$r\n";


    package Regex;

    sub new {
    my ( $class, $re) = @_;
    bless { re => qr/$re/, capt => [] }, $class;
    }

    sub match {
    my ( $r, $str) = @_;
    @{ $r->{ capt} } = $str =~ /($r->{ re})/;
    return scalar @{ $r->{ capt} };
    }

    use overload '@{}' => sub { shift()->{ capt} };
    __END__
    -berlin.de, Jul 31, 2007
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. C
    Replies:
    0
    Views:
    490
  2. Emin
    Replies:
    4
    Views:
    407
    Paul McGuire
    Jan 12, 2007
  3. ABCL
    Replies:
    0
    Views:
    543
  4. Skybuck Flying
    Replies:
    30
    Views:
    1,094
    Bill Reid
    Sep 19, 2011
  5. C
    Replies:
    3
    Views:
    215
    Manohar Kamath [MVP]
    Oct 17, 2003
Loading...

Share This Page