Skip Menu |
Report information
Id: 128955
Status: new
Priority: 0/
Queue: perl6

Owner: Nobody
Requestors: zefram [at] fysh.org
Cc:
AdminCc:

Severity: (no value)
Tag: Bug
Platform: (no value)
Patch Status: (no value)
VM: (no value)



From: Zefram <zefram [...] fysh.org>
Date: Tue, 16 Aug 2016 01:38:08 +0100
Subject: [BUG] Pair.freeze breaks Set behaviour
To: rakudobug [...] perl.org
Download (untitled) / with headers
text/plain 3.8k
Show quoted text
> my $a = 3; my $b = :$a; my $c = set($b, (:3a)); $b.freeze; my $d = $c.List.Set; say $c.elems; say $d.elems
2 1 The $b.freeze call mutates the Pair object $b in a way that changes its identity as perceived by the Set class. That's a problem. The set $c is created containing two distinct elements. After $b.freeze, the two elements now appear to be identical, so putting the elements into a List and turning that back into a Set coalesces them, yielding the singleton set $d. So $c is a set containing the same element twice, fundamentally breaking the concept of a set. Or, from another point of view, it actually contains one element but erroneously thinks its cardinality is two. The Set->List->Set transformation should always yield a set identical to the original, but that doesn't hold for this broken set. The change that the Set class pays attention to is a change in the .WHICH value: Show quoted text
> my $a = 3; my $b = :$a; say $b.WHICH; $b.freeze; say $b.WHICH
Pair|47804663822576 Pair|Str|a|Int|3 Ostensibly, this change in the .WHICH value indicates that the object has become a different object, while remaining the same object in the sense that references to the original object now refer to the new object. For this to happen to a fully-constructed object breaks all kinds of uses for .WHICH. Indeed, doc/Type/Mu.pod says of the return value of .WHICH that it "uniquely identifies the object", and such a changeable value can't really be said to *identify* the object at all. This question of Pair.WHICH interacts with [perl #128948]. I commented there that I didn't think a container-referencing Pair was mutable to the extent of being changeable to refer to a different container. With the .freeze method in play, I was wrong about that: a Pair is truly mutable. Indeed, where on that ticket I pointed to an inability to make my two Pairs behave differently, with .freeze I can: Show quoted text
> my $a; my $b = :a($a); my $c = :a($a); $b.value = (my $ = 5).VAR; $b.freeze; $c.value = 7; $b.perl, $c.perl
(:a(5) :a(7)) If this is the intended semantic for Pair, then the "Pair|47804663822576" style .WHICH value makes perfect sense. It is identifying the unique mutable storage location provided by the Pair object. However, to avoid breaking the basic semantics of .WHICH (and thus the Set class), a Pair that gets frozen needs to retain its original .WHICH value, not switch to the functional style. Its identity is still based on the Pair's mutable storage location, even if the public API no longer permits it to be mutated. If it was ever mutable, its identity is that of a mutable object. Thus each Pair object needs a flag to say which kind of identity it has. It is not sufficient to (as at present) just look at whether the current value is a container. If one wants to avoid needing the flag, the only other option is for *all* Pair objects to get mutable-style .WHICH values. This would mean no more functional Pairs; even Pairs which have immutable values from birth would have distinct identity based on physical storage. That would be a major change, and an unfortunate loss of good semantics. However, it doesn't look to me as though the Pair class was really intended for this kind of mutability. The .freeze method looks like an afterthought, added without noticing the violence it does to object identity and the class's concept. It looks to me as though a Pair was intended to be an immutable object, unchangeably referencing its key and value. Of course the value can itself be a mutable object, but as I pointed out in [perl #128948] that doesn't amount to the Pair being mutable. If the .freeze method is removed, then the problem with .WHICH and Set cannot arise. Also, as I said on the other ticket, the appropriate kind of .WHICH value for a Pair immutably referencing a particular Scalar container would be not "Pair|47804663822576" but "Pair|Str|a|Scalar|47608575457088". -zefram


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org