Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pair.freeze breaks Set behaviour #5581

Open
p6rt opened this issue Aug 16, 2016 · 1 comment
Open

Pair.freeze breaks Set behaviour #5581

p6rt opened this issue Aug 16, 2016 · 1 comment
Labels

Comments

@p6rt
Copy link

p6rt commented Aug 16, 2016

Migrated from rt.perl.org#128955 (status was 'new')

Searchable as RT128955$

@p6rt
Copy link
Author

p6rt commented Aug 16, 2016

From zefram@fysh.org

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant