[Israel.pm] Python talk

Gaal Yahas gaal at forum2.org
Tue Dec 7 06:36:41 PST 2004


On Tue, Dec 07, 2004 at 07:23:39AM +0000, Mikhael Goikhman wrote:
> > COMPLICATED_ASSOC_ARRAY = {
> >   (0,0) : { "label" : "Origin of the World", "population" : 0 },
> >   (0,90): { "label" : "North Pole", "population" : "varies, usually 0"},
> >   (0,-90):{ "label" : "South Pole", "population" : ("penguins",10E6)}
> > }
> 
> Ok, Perl only allows strings or numbers to be the hash keys.

To be precise: Perl allows only strings as hash keys. (Look at hv.c to
see how there's only a char*+length in the implementation.) Numbers get
stringified, and if you have a dual value, the string part will be used.

> But to simulate keys that are arrays, you may map array to string. So
> here is the Perl code:
> 
> $COMPLICATED_ASSOC_ARRAY = {
>   '0,0'   => { label => 'Origin of the World', population => 0 },
>   '0,90'  => { label => 'North Pole", population => 'varies, usually 0' },
>   '0,-90' => { label => 'South Pole", population => [ penguins => 10E6 ] },
> }
> 
> To get the array back from the key (if you ever need this), you may split
> the key by the separator, or better store the array in the hash too, ie.:
> 
>   { label => 'somewhere', population => 12, time => [ 10, 20 ] }

Generalized, this is simply an explicit serialization technique. Uri
points out that Perl has an automatic serialization for lists, which
has a few gotchas but can be useful if applied carefully.

> And if the keys are constant arrays and not variable arrays, then you
> don't even need to join the array elements to construct the key (but you
> should be aware that Perl converts arrayref to string here):
> 
>   $time = [ 100, 200 ];
>   $CAA->{$time} = { label => 'somewhere', population => 12, time => $time };

You can run into bugs with this strategy, if you're not careful. Say you
undef $time (explicitly or through reference counting). Nothing prevents
perl from using the memory once taken by the old [ 100, 200 ] to some new
arrrayref you've created, and then when you perform another lookup you
get stale data. Of course careful coding can help here, but it does mean
the programmer now has to think of one more thing.

> I used both methods (string as keys and arrayrefs as keys) to solve such
> tasks, and it works well, it even works with hashrefs as keys, something
> that Python does not support. All in all, I don't think that working with
> arrays as the keys is more intuitive than working with strings as the
> keys. And I don't see anything real-life fundamental that Perl misses.
 
I think Omer's example was a good one. It's *reasonable* to want to map
coordinates to additional metadata. A tuple when used like that isn't an
object that can go out of scope, so there aren't any risks of the type
mentioned above. I wonder about the broader semantics Python provides
(if indeed it does) for using objects as keys. Does the reference count
increase? Can you destruct an object manually from outside the hash and
have the hash remove it automatically? (This can be useful in some cases!)

> Does someone know whether Perl 6 will allow any object to be hash key?

Yes, it will. From Synopsis 9 <http://dev.perl.org/perl6/synopsis/S09.html>:

	To declare a hash that can take any object as a key rather than
	just a string, say something like:

		my %hash is shape(Any);

	Likewise, you can limit the keys to objects of particular types:

		my Fight %hash is shape(Dog;Cat);

	The standard Hash is just

		my Any %hash is shape(Str);

	Note that any type used as a key must be intrinsically immutable,
	or it has to be able to make a copy that functions as an immutable
	key, or it has to have copy-on-write semantics. It is erroneous
	to change a key object's value within the hash except by deleting
	it and reinserting it.

-- 
Gaal Yahas <gaal at forum2.org>
http://gaal.livejournal.com/



More information about the Perl mailing list