Mailing List Archive

bug in hash assignment..
Re: bug in hash assignment.. [ In reply to ]
On Sun, 29 Oct 1995, Ed Peschko wrote:

> hey all --
>
> I noticed the following problem...
>
> if you are doing multiple arrayed hashes -- ie:
>
> $hash{'a'}{'b'};
>
> and you so happen to use a hash that has an undefined value in the first
> element in a comparison -- ie:
>
> undef %hash;
> if ($hash{'aaa'}{'bbb'} eq 1 ) {
> # do something...
> }
>
> print keys(%hash);
>
> This code snippet will print out 'aaa'.. ie -- the anonymous hash ref to
> aaa is not getting destroyed at the end of the comparison...

Interesting. I'm not certain this can be classified as a bug, more as
"behaviour". Perl has to auto-create the anonymous hash ref in the 'aaa'
slot, and that's going to be a different operation from the "is there a
'bbb' key?".

I haven't looked at the code yet, but if it isn't already doing something
like this, it seems like the parse would have to work out whether a
ref-generating lookup is an lvalue or lvalue, and prepare to undo the ref
creations if the interior lookup fails... Hmm... If the interior lookup
is equated to non-zero, then a lookup that creates a ref _must_ fail, so
it seems like there is an oppurtunity for optimization here.

To get back to your problem, though, it might actually be _more_ efficient
to let it work the way it does now, since if you are repeatedly looking up
that key, then a succeeding lookup should cost less then a failed lookup
and a hash creation.

> Ed

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: bug in hash assignment.. [ In reply to ]
Re: bug in hash assignment.. [ In reply to ]
On Mon, 30 Oct 1995, Ed Peschko wrote:

> Yes.. but unfortunately, I was under the (mis) understanding that this didn't
> occur.. and was using a multi-dimensional hash to hold things such as a 'before
> and after' snapshot of columns in a table: ie:
>
> if ($table_old{$column}{'type'} ne $table_new{$column}{'type'}) {
> ...
> }
>
> Unfortunately... this makes an array ref so now
>
> @keys_old = keys(%table_old);
> @keys_new = keys(%table_new);
>
> grep ($MARK{$_}++, @keys_old);
> @reslt = grep($MARK{$_}, @keys_new);
>
> is useless...

Well, you might like to try this:

if (((not $table_old{$column}) xor (not $table_new{$column})) or
$table_old{$column}{'type'} ne $table_new{$column}{'type'}) {
...
}

Or for efficiencies sake:

if (((not ($old=$table_old{$column})) xor (not
($new=$table_new{$column}))) or
$old->{'type'} ne $new->{'type'}) {
...
}

Er, not quite. How about:

$old=$table_old{$column};
$new=$table_new{$column};
if(($old xor $new) or (($old and $new) and ($old->{'type'} ne
$new->{'type'}))) {
...
}

Hardly compact, I'll admit. This is a bit better.

$old = $table_old{$column};
$old &&= $old->{'type'};
$new = $table_new{$column};
$new &&= $new->{'type'};
if($old ne $new) {
...
}

> Ed
>

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: bug in hash assignment.. [ In reply to ]
Re: bug in hash assignment.. [ In reply to ]
>>>>> "Ed" == Ed Peschko <epeschko@animas.tcinc.com> writes:

Ed> Yes.. but unfortunately, I was under the (mis) understanding that this didn't
Ed> occur.. and was using a multi-dimensional hash to hold things such as a 'before
Ed> and after' snapshot of columns in a table: ie:

Ahh... so there's your problem. You think that what you have here is
a multidimensional hash. The syntax even tricks you into thinking
that you have that. But you don't. Perl doesn't have either
multidimensional hashes or lists of lists. It has hashes of
references to hashes, and lists of references to lists, that can be
used to *pretend* that you have those other things, but if you push
the pretense too far, you can see that it breaks.

This is why I can't teach:

$a[35][12]

in day two of my Learning Perl class, even when people say "so, are
there multidimensional arrays?". My answer to this is "*no*, but wait
until we get all comfortable with the fact that that there isn't and
then I'll show you (bit by bit) how to use pointers to pretend that
there are."

Because remember, this is only a shorthand for:

$a[35]->[12]

and that arrow cannot really be eliminated. $a[35] is a real thing:
it's a ref to an anon-list, and we're looking at element index 12 of
that list. So to know what this is doing, you have to bring in all of
the ref technology and understanding, building it up slowly from "what
does \@anarray mean?".

Sorry for going off like this, but I think we just can't hide behind
the "perl has multidim lists and hashes now!" banner. It doesn't have
it, but it has things that can pretend, as long as you know it's just
pretend.

I'm also struggling with these very issues for the appropriate section
of the new camel book. So I'm in the midst of this stuff.

Name: Randal L. Schwartz / Stonehenge Consulting Services (503)777-0095
Keywords: Perl training, UNIX[tm] consulting, video production, skiing, flying
Email: <merlyn@stonehenge.com> Snail: (Call) PGP-Key: (finger merlyn@ora.com)
Web: <A HREF="http://www.teleport.com/~merlyn/">My Home Page!</A>
Quote: "I'm telling you, if I could have five lines in my .sig, I would!" -- me
Re: bug in hash assignment.. [ In reply to ]
>in day two of my Learning Perl class, even when people say "so, are
>there multidimensional arrays?". My answer to this is "*no*, but wait
>until we get all comfortable with the fact that that there isn't and
>then I'll show you (bit by bit) how to use pointers to pretend that
>there are."

I assume you teach C programmers that there are no multidimensional
arrays either, and that argv[0][0] isn't really the first character
of your program name?

I don't think so.

>Sorry for going off like this, but I think we just can't hide behind
>the "perl has multidim lists and hashes now!" banner.

Well, I certainly think you can. But I teach it out of the PDSC, which
actually does explain these things.

--tom
Re: bug in hash assignment.. [ In reply to ]
: >>>>> "Ed" == Ed Peschko <epeschko@animas.tcinc.com> writes:
:
: Ed> Yes.. but unfortunately, I was under the (mis) understanding that this didn't
: Ed> occur.. and was using a multi-dimensional hash to hold things such as a 'before
: Ed> and after' snapshot of columns in a table: ie:
:
: Ahh... so there's your problem. You think that what you have here is
: a multidimensional hash. The syntax even tricks you into thinking
: that you have that. But you don't. Perl doesn't have either
: multidimensional hashes or lists of lists. It has hashes of
: references to hashes, and lists of references to lists, that can be
: used to *pretend* that you have those other things, but if you push
: the pretense too far, you can see that it breaks.

Randal, you're getting a bit carried away here. This has little to do
with the bug, which is that autovivificaion should never happen in an
rvalue context. Even if you think of $a[35][12] as $a[35]->[12], it's
still a bug, as far as I'm concerned. I never intended $a[35]->[12] to
autovivify $a[35] in an rvalue context. I'm embarrassed that it does,
and intend to figure out why it does. The earliest version of Perl 5
were written to propagate undefness outward through all the subscripts
in an rvalue context, and I (or we) must have screwed it up somewhere
along the way since then.

: This is why I can't teach:
:
: $a[35][12]
:
: in day two of my Learning Perl class, even when people say "so, are
: there multidimensional arrays?". My answer to this is "*no*, but wait
: until we get all comfortable with the fact that that there isn't and
: then I'll show you (bit by bit) how to use pointers to pretend that
: there are."
:
: Because remember, this is only a shorthand for:
:
: $a[35]->[12]
:
: and that arrow cannot really be eliminated. $a[35] is a real thing:
: it's a ref to an anon-list, and we're looking at element index 12 of
: that list. So to know what this is doing, you have to bring in all of
: the ref technology and understanding, building it up slowly from "what
: does \@anarray mean?".

If they have to have all that knowledge to use $a[35][12] then Perl
is busted. (And in this case, it is.) I don't want Perl to become a
language where you have to know all the intricacies before you can
use it usefully. And multi-dimensional arrays are a very useful
concept.

: Sorry for going off like this, but I think we just can't hide behind
: the "perl has multidim lists and hashes now!" banner. It doesn't have
: it, but it has things that can pretend, as long as you know it's just
: pretend.
:
: I'm also struggling with these very issues for the appropriate section
: of the new camel book. So I'm in the midst of this stuff.

Some things can best be taught by lying first, and telling the truth later.

I would say that the answer to the question in question is, "Er, yes,
Perl has multi-dimensional arrays. They're implemented as arrays of
refs to arrays." Multi-dimensionality is a mathematical concept, not a
memory layout. When the implementation interferes with the concept,
we oughta fix the implementation, not the concept.

Larry