Skip Menu |
Report information
Id: 131887
Status: open
Priority: 0/
Queue: perl6

Owner: Nobody
Requestors: p.dumarchie [at] gmail.com
Cc:
AdminCc:

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



Subject: [BUG] method freeze(Pair:D:) changes object identity
From: Peter du Marchie van Voorthuysen <p.dumarchie [...] gmail.com>
Date: Sat, 12 Aug 2017 14:35:54 +0200
To: rakudobug [...] perl.org
Download (untitled) / with headers
text/plain 2.3k
This is Rakudo version 2017.07 built on MoarVM version 2017.07
implementing Perl 6.c.

If the value of a Pair is a Scalar container, then the Pair can be modified, e.g.

    > my $value = 0;
    0
    > my $pair = number => $value;
    number => 0
    > $pair.value = 1; $pair;
    number => 1

Method freeze make the value of the Pair read-only, by removing it from its Scalar container, and returns the value.

    > $pair.freeze;
    1
    > $pair.value = 2;
    Cannot modify an immutable Int (1)
      in block <unit> at <unknown file> line 1

The problem is that freeze does more than that. It changes the object identity as returned by WHICH as well:

    > $pair = number => $value;
    number => 1
    > $pair.WHICH;
    Pair|127791728
    > $pair.freeze;
    1
    > $pair.WHICH;
    Pair|Str|number|Int|1

Now by itself having a 2-tuple that is identified by its two elements is a nice feature (if it would be documented). But _changing_ the object identity is not consistent with the behavior of other built-in Perl 6 classes and actually breaks the implementation of some of these classes.

For example, a SetHash represents a mutable set. The Set method returns a _new_ object that is immutable:

    > $pair = number => $value;
    number => 1
    > my $set = SetHash.new($pair);
    SetHash.new(number => 1)
    > my $set2 = $set.Set;
    set(number => 1)
    > $set.WHICH;
    SetHash|136539408
    > $set2.WHICH;
    Set|0EC3BFFD57719F5C6A3EE91A5EFAA5AEFE273964

But because freezing a Pair changes the identity of the _original_ object it's possible to add a second instance of the _same_ Pair to the SetHash, causing it to violate its contract:

    > $pair.freeze;
    1
    > $set{$pair} = True;
    True
    > my ($a, $b) = $set.keys;
    (number => 1 number => 1)
    > $a === $b;
    True

I think it's clear that changing the identity of the original object is not correct. So I propose to remove the undocumented behavior of the freeze method that it changes the object identity.

Now I can imagine that at some implementation level there are benefits to having a kind of Pair that is identified by its key _and_ value. I also think it could be generally useful to have a class implementing a truly immutable (2-)tuple that is identified by its elements. But that should be a separate class and the Pair class should provide a method to create a _new_ object of this class from a Pair object.
Date: Mon, 14 Aug 2017 00:14:18 +0200
To: "Peter du Marchie van Voorthuysen (via RT)" <perl6-bugs-followup [...] perl.org>
Subject: Re: [perl #131887] [BUG] method freeze(Pair:D:) changes object identity
From: Elizabeth Mattijsen <liz [...] dijkmat.nl>
Download (untitled) / with headers
text/plain 2.8k
Fixed with https://github.com/rakudo/rakudo/commit/c229022cb0 , tests needed Show quoted text
> On 12 Aug 2017, at 14:36, Peter du Marchie van Voorthuysen (via RT) <perl6-bugs-followup@perl.org> wrote: > > # New Ticket Created by Peter du Marchie van Voorthuysen > # Please include the string: [perl #131887] > # in the subject line of all future correspondence about this issue. > # <URL: https://rt.perl.org/Ticket/Display.html?id=131887 > > > > This is Rakudo version 2017.07 built on MoarVM version 2017.07 > implementing Perl 6.c. > > If the value of a Pair is a Scalar container, then the Pair can be > modified, e.g. >
>> my $value = 0;
> 0
>> my $pair = number => $value;
> number => 0
>> $pair.value = 1; $pair;
> number => 1 > > Method freeze make the value of the Pair read-only, by removing it from its > Scalar container, and returns the value. >
>> $pair.freeze;
> 1
>> $pair.value = 2;
> Cannot modify an immutable Int (1) > in block <unit> at <unknown file> line 1 > > The problem is that freeze does more than that. It changes the object > identity as returned by WHICH as well: >
>> $pair = number => $value;
> number => 1
>> $pair.WHICH;
> Pair|127791728
>> $pair.freeze;
> 1
>> $pair.WHICH;
> Pair|Str|number|Int|1 > > Now by itself having a 2-tuple that is identified by its two elements is a > nice feature (if it would be documented). But _changing_ the object > identity is not consistent with the behavior of other built-in Perl 6 > classes and actually breaks the implementation of some of these classes. > > For example, a SetHash represents a mutable set. The Set method returns a > _new_ object that is immutable: >
>> $pair = number => $value;
> number => 1
>> my $set = SetHash.new($pair);
> SetHash.new(number => 1)
>> my $set2 = $set.Set;
> set(number => 1)
>> $set.WHICH;
> SetHash|136539408
>> $set2.WHICH;
> Set|0EC3BFFD57719F5C6A3EE91A5EFAA5AEFE273964 > > But because freezing a Pair changes the identity of the _original_ object > it's possible to add a second instance of the _same_ Pair to the SetHash, > causing it to violate its contract: >
>> $pair.freeze;
> 1
>> $set{$pair} = True;
> True
>> my ($a, $b) = $set.keys;
> (number => 1 number => 1)
>> $a === $b;
> True > > I think it's clear that changing the identity of the original object is not > correct. So I propose to remove the undocumented behavior of the freeze > method that it changes the object identity. > > Now I can imagine that at some implementation level there are benefits to > having a kind of Pair that is identified by its key _and_ value. I also > think it could be generally useful to have a class implementing a truly > immutable (2-)tuple that is identified by its elements. But that should be > a separate class and the Pair class should provide a method to create a > _new_ object of this class from a Pair object.


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