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

Dear Monks,

I write you this question with happy feelings on one side, as I was able to solve some (for me) very hard problems of a project Iīm working on. On the other side, now Iīm stuck in the "technically elegant" mania and the Perl characteristics donīt seem to allow me things I would like to do.

I have 3 object classes. Letīs call them Dictionary, Entry and Parser.

Dictionary has the following constructor:

sub new { my $pkg = shift; my %dictionary; my $self = \%dictionary; bless $self, $pkg; }
Entry has the following constructor (as of now):
sub new { my $pkg = shift; my $self = \\@_; bless $self, $pkg; }
The constructor of Parser is irrelevant - I just donīt know it Parse::RecDescent creates it.

Now Dictionary shall be a hash of Entries, where each Entry is a List of something. A Parser object creates (allocates) this list and returns a reference to it. Thus my first shot at Entry was:

sub new { my $pkg = shift; my $self = \@_; bless $self, $pkg; }
However - I wasnīt able to "pass this reference" returned from Parser to the reference member of the Entry object. Someone here at the Chatterbox told me, that this indeed isnīt possible and that I have to use a reference to a reference as element of the object. Therefore the \\@_.

This seems contraintuitive to me. But wait! Thereīs more:

So Now I have those reference to a reference Entry objects and adjusted my code to cope with it. But now the problems keep in coming. I wrote a simple method in the Entry Class just for debugging purposes, that shall print the contents of the list Entry points to:

sub eprint { my $self = shift; my $key = shift; print "KEY: $key\n"; foreach my $show (@{$self}) { print "element: $show\n"; } }
This works nice, as long as I have really a reference to a reference at hand:
$self->{$key} = $$entry; # anchor reference in dictionary $entry->eprint($key); # just for debug purpose (WORKS)
If I donīt, hell breaks loose:
# remeber: value of the hash-element with # key $k1 is an Entry object my $ref1 = $dictionary{$l1}->{$k1}; # works foreach my $meaning (@{$ref1}) { &message("\t$meaning\n"); } $ref->eprint($k1); # no chance :-(
Now what would be ideal? Ideal would be, If I wouldnīt need to have a reference to a reference stored in Entry but just reference to list. And if I could use Entry-methods consistently through my code.

Any help - as always my patient brothers - is greatly apreciated.

Ciao
Rico

BTW: Nodes read before writing this Node: 81683 76071 51815 (could here be a hidden answer?) 21775 20664 19121 and many others...

Replies are listed 'Best First'.
(tye)Re: Reference as the only Object element
by tye (Sage) on Nov 02, 2001 at 21:12 UTC

    Try $self= [@_]; [(update2) in place of $self= \\@_;].

    Update: I'd say more but I can't figure out what

    I wasnīt able to "pass this reference" returned from Parser to the reference member of the Entry object.
    means. I was around when
    Someone here at the Chatterbox told me, that this indeed isnīt possible
    and I'll wager that we didn't understand what was being asked.

    Anyway, I wouldn't ever put \@_ into an object as changes to @_ would be reflected in the object and I'm not sure what changes Perl itself might make to @_ when the subroutine exits. Also, the elements of @_ are aliases to the arguments passed in (that is \$_[0] == \$arg0) so changing $_[0] changes the variable (in the caller) that was passed in and vice versa. But [@_] creates a new anonymous array and copies the elements of @_ into it and so shouldn't suffer from these two problems.

    But none of that explains to me why \\@_ would work. /:

            - tye (but my friends call me "Tye")
      > Try $self=[@_];

      Where? :-)

      What I mean with "pass this reference" is actually "clone a reference". Again assume you have a parser and this parser is filling you a structure (basically a list). You let your parser return a reference to the structure created and you would like your Entry Object to store THAT Reference.

      This seems not possible. BTW: You throw up an interesting point:

      >Anyway, I wouldn't ever put \@_ into an object as changes...

      How do you declare an object whose only element is a reference to a list (or hash for that matter)?

      Thanks Richard

        You're confusing the implentation of the object and the attributes of that object.

        If you want to declare an object which is implented as a list, I'd do something like:

        sub new { my $class = shift; my $self = [@_]; bless $self, $class; return $self; } sub getList { my $self = shift; if (wantarray) { return @$self; else { return [@$self]; } }

        If you wanted to have a class which had only one attribute and that attribute was a list, I'd do something like:

        sub new { my $class = shift; my $self = {}; bless $self, $class; $self->{LIST} = [@_]; return $self; } sub getList { my $self = shift; if (wantarray) { return @{$self->{LIST}}; else { return [@$self->{LIST}]; } }
        Then, you would add setters as well. However, we already have something like this, in the form of tie and Tie::Array (and its cousin Tie::Hash). Check those out.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

Re: Reference as the only Object element
by dragonchild (Archbishop) on Nov 02, 2001 at 21:40 UTC
    Ok. Let me get this straight. You have a container object which does a mapping between some set of identifier and some set of other objects. Sounds pretty simple to me.

    I think your confusion lies in the implementation details. You're not seeing the forest for the trees. Step back a moment and let's design this, then implement it.

    You have some container object. That container object shouldn't care what objects it contains. More specifically, it shouldn't care how those objects are implemented.

    This would mean that instead of doing @{$self->{$key}}, you would do something like @{$self->{$key}->getList}. This allows the contained object to determine how to store itself. In addition, it allows for your container to store more than one type of object.

    So, what this means is you have to create a bunch of methods that will do stuff, like get the list being stored in the inner object.

    Does this make sense so far?

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.