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]