# New Ticket Created by  Zefram 
# Please include the string:  [perl #128955]
# in the subject line of all future correspondence about this issue. 
# <URL: https://rt.perl.org/Ticket/Display.html?id=128955 >


> 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:

> 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:

> 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

Reply via email to