Ovid <[EMAIL PROTECTED]> writes:

> --- Barry Jones <[EMAIL PROTECTED]> wrote:
>> If I have a hash full of values, and some of those values point to
>> arrays of more values...in a loop, how could I distinguish which ones
>> pointed to an array and which were just string values?
>
> Barry,
>
> Use the 'ref' function for this:
>
>     perldoc -f ref
>
> One caveat, though: most uses of 'ref' seem wrong.  Generally
> speaking, whenever I am tempted to use ref on vanilla code, I
> discover that I could simplify what I meant to do.  In your case,
> have you considered making every value an array reference?  If you
> only have a scalar, you have a one-element array ref.  Generally,
> when I rework the code to eliminate the need for 'ref', I discover
> that my code is shorter and easier to maintain.
>
> I'm not saying that you've done anything wrong, of course.  I'm just
> suggesting that you might want to give the code a second look.

Depending on what the hash is being used for and whether the structure
is arbitrary, this may be a good time pull out the old OO toolkit,
specifically the 'Composite' and 'Visitor' patterns.

The idea here is that you have a treelike data structure made up of
containers and 'terminals'. You could then setup some classes like so:


package Container;

sub accept {
    my $self = shift;
    my($visitor) = @_;
    
    $visitor->visit_container($self);
    foreach my $element ($self->contents) {
        $element->accept($visitor);
    }
    $visitor->leave_container($self);
}

sub contents {
    my $self = shift;
    wantarray ? @{$self->{contents}} : $self->{contents};
}

sub name {
    my $self = shift;
    $self->{name};
}
    

package Terminal;

sub accept {
    my $self = shift;
    my($visitor) = @_;
    
    $visitor->visit_terminal($self);
}

sub name {
    $self->{name};
}

So, suppose we use this data structure to represent a filesystem and
we want to list all the files in it, so, we write ourselves a visitor:

package FileLister;

sub visit_container {
    my $self = shift;
    my($directory) = @_;

    $self->push_path($directory->name);
}

sub visit_terminal {
    my $self = shift;
    my($file) = @_;

    print join '/', $self->path, $file->name;
}

sub leave_container {
    my $self = shift;
    my($directory) = @_;

    ($directory->name eq $self->pop_path) or
        die "Something very strange happened";
}

NB: This is very skeletal there's no denyinig. Implementing
constructors, other accessor methods and all the other paraphenalia of
a fully functional class is left as an exercise for the interested
reader. 

This is a very powerful approach; you'll come across it in all manner
of places. There's all sorts of wrinkles you can add, for instance,
you might extend the interface to allow the various vist_* methods to
prune the tree walk by cunning use of return values or exceptions.

There's no denying that it carries a bunch of overhead with it though,
and it's not suited to everything; but it's a useful tool to know
about.


-- 
Piers

   "It is a truth universally acknowledged that a language in
    possession of a rich syntax must be in need of a rewrite."
         -- Jane Austen?


-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to