develooper Front page | perl.perl5.porters | Postings from July 2001

[Help] Salvage the Array Hash Monster.

Thread Next
Autrijus Tang
July 26, 2001 20:03
[Help] Salvage the Array Hash Monster.
Message ID:
Since the announcement that phash will be out of v5.10 was made 
(a decision I found reasonable and fully support), I've been
thinking about how to implement the interface
(cf. <>)
in newer versions of perl. That is, whether it will be feasible 
to make a reference that behaves both as an array reference and 
a hash reference, so you can say:

    use ArrayHashMonster;
    my $dualref = ArrayHashMonster->new(
	[1..9], {bar => 'baz', 'foo' => 'fie'}
    print $dualref->[-1];   # 9
    print $dualref->{bar};  # baz
    print keys %{$dualref}; # foobar
    print  for @{$dualref}; # 123456789

I'm aware that one can overload deferencing operators for @{} and
%{} constructs, but that's inadequate for slice access and other

This is not a purely theoretical question. About one year ago I 
cleaned up the AHM, and applied to my work on providing tied 
variable access to PlRPC (OurNet::BBS::Server/Client), as well as 
the dynamic backend system of the OurNet library (OurNet::BBS::Base 
and OurNet::BBS::ArrayProxy on CPAN).

I'm also aware that I should not deploy production code that
depends on an experimental feature, and as tchrist recommended 
after his TPC5 Guru Session, it's true that I could discourage 
all sysadmin of OurNet nodes from installing v5.10. But we 
really need i18n features that didn't come until 5.8+, so it's
not a happy solution.

mjd says he'll fix it by producing a core patch that lets you say

    our (@data, %data);
    tie @data, 'ArrayMonster', (1..9);
    tie %data, 'HashMonster', (bar => 'baz', foo => 'fie');
    my $dualref = *data;
    print $dualref->{bar}; # instead of $*dualref or something

But I found out latter that it already works as of v5.6.1. The
problem of this approach is that @data and %data have to be 
package variables instead of lexicals, which cannot be 
automatically DESTROY'ed, among other drawbacks.

Of course, one can bless $dualref into a package that provides
a DESTROY method, which manually calls @data and %data's DESTROY
methods. But one will have to maintain the reference count (maybe
stored in $data) by hand, so "my $anotherref = *data" will still 
work after $dualref goes out of scope. I'm not sure whether
this approach will work, but if nothing else comes up I'll
fall back to it.

tchrist also said something like trying to bind lexical variables
to (also lexical) gensym globs, but Jarkko and I worked on that
for a while and found out it doesn't work currently, i.e. one
cannot write:

    use Symbol;
    my $dualref = gensym;
    tie my @data, 'ArrayMonster', (1..9);
    tie my %data, 'HashMonster', (bar => 'baz', foo => 'fie');
    $dualref = \@data; # XXX wouldn't work, overwrites the glob
    $dualref = \%data; # XXX ditto

Which is quite unfortunate. To do that, one will need to alias
@Symbol::GENxx to @data (or the other way around), and still
let @data remain lexical. This might be accomplished by writing 
a XS extension that binds lexical variables to anonymous globs:

    use Symbol;
    use Inline C => q{
	# some magic we have yet to invent: bindarray and bindhash 
    my $dualref = gensym;
    bindarray($dualref, [1..9]);
    bindhash($dualref, {bar => 'baz', foo => 'fie'});

But since all gensym does is just returning *Symbol::GENx and 
delete it from the symbol table, there's nothing fancy with the 
glob it returned. Hence it will take more than a trivial core 
patch to allow perl to associate globs that has its *ARRAY 
and *HASH values pointed to lexical variables.

I'm sure there's more elegant approaches to this problem, and
I'd be very grateful if somebody in p5p could enlighten me
on it.

Thanks in advance,


Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About