develooper Front page | perl.perl5.porters | Postings from February 2000

Re: [PATCH 5.5.660] improved semantics for assign to pseudohash

From:
Michael G Schwern
Date:
February 28, 2000 02:58
Subject:
Re: [PATCH 5.5.660] improved semantics for assign to pseudohash
Message ID:
20000228055836.A25518@athens.aocn.com
On Sun, Feb 27, 2000 at 07:44:00AM -0500, John Tobey wrote:
> > > +OP *
> > > +Perl_ck_aassign(pTHX_ OP *o)
> > > +{
> > > +    OP *kid;
> > > +    kid = ((LISTOP*)cBINOPo->op_first->op_sibling)->op_last;
> > > +    if (kid->op_type == OP_RV2HV || kid->op_type == OP_PADHV)
> > > +	o->op_flags |= OPf_SPECIAL;
> > >      return o;
> > >  }

I was more curious about this particular statement:

        kid = ((LISTOP*)cBINOPo->op_first->op_sibling)->op_last;

Ops are still something of a blackbox to me.  I think I've figured it
out myself, but could you walk me through it?  I kind of understand
what it does, just not why.


> > BTW Does it handle (%$ph, @a) = @list; and (@a, %$ph) = @list; and
> > ($a, %$ph) = @list properly?
> 
> No, yes, and yes, I think.  Perl_ck_aassign needs to be changed so
> that it looks at the first hash-or-array on the left side instead of
> simply the last element as it does now.

Okay, I've made some progress.  I altered Perl_ck_aassign:

Perl_ck_aassign(pTHX_ OP *o)
{
    OP *kid;
    for( kid = ((LISTOP*)cBINOPo->op_first->op_sibling)->op_first;
         kid;
         kid = kid->op_sibling
       )
    {
        if (kid->op_type == OP_RV2HV || kid->op_type == OP_PADHV)
            o->op_flags |= OPf_SPECIAL;
    }
    return o;
}

Walk through everything on the left hand side of the assignment, not
just the first.  This should nail all combinations of (EXPR, %$avhv) =
@list and (%$avhv, EXPR) = @list;  Hope its not overkill.

Here's the problem.  I added a few more tests to t/op/avhv.t...

my $extra;
my @extra;
($extra, %$avhv) = ("moo", foo => 42, pants => 53, bar => "HIKE!");
print "not " unless "@$avhv[1..3]" eq '42 HIKE! 53' and $extra eq 'moo';
print "ok 25\n";

%$avhv = ();
(%$avhv, $extra) = (foo => 42, pants => 53, bar => "HIKE!");
print "not " unless "@$avhv[1..3]" eq '42 HIKE! 53' and !defined $extra;
print "ok 26\n";

@extra = qw(whatever and stuff);
%$avhv = ();
(%$avhv, @extra) = (foo => 42, pants => 53, bar => "HIKE!");
print "not " unless "@$avhv[1..3]" eq '42 HIKE! 53' and @extra == 0;
print "ok 27\n";

%$avhv = ();
(@extra, %$avhv) = (foo => 42, pants => 53, bar => "HIKE!");
print "not " unless ref $avhv[0] eq 'HASH' and @extra == 6;
print "ok 28\n";

25 and 26 it handles fine.  Problem is 27 and 28, they fail.  I have
an idea why:

In 27 @extra is coming out with ('whatever') instead of being cleared.
I originally thought it was being misinterpreted as a pseudohash, thus
element 0 wouldn't be cleared, but its not.  When it gets to
aassign(), for some odd reason relem is "whatever".  I have no idea
why.  Other than that little glitch it works.  (@foo, @bar) = @list;
doesn't show the same behavior.

In 28 %$avhv is getting completely cleared.  I figure there's some
sort of optimization that's screwing with it and still does the naive
case, treating it as an array.  aassign() it still treating it as a
pseudohash, but the time it gets there its completely cleared.  I
didn't see anything obvious in the peephole and nothing is calling
av_clear() that I can see (except to set @ARGV).

-- 

Michael G Schwern      http://www.pobox.com/~schwern/      schwern@pobox.com
But folks don't get me wrong.   Jews are not antichrists.  Only Karl Marx was for he has created communism.
             --Alex Chiu, Immortality Guy



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About