On 23/11/2024 16:05, Rob Landers wrote:
Your RFC doesn't discuss this - the changeName example shows behaviour
*inside* the method, but not behaviour when *calling* it

An interesting observation, can you explain more as to what you mean?

Looking closer, there's a hint at what you expect to happen in your Rectangle example:

$bigRectangle = $rectangle->resize(10, 20);
assert($bigRectangle !== $rectangle); // true

It seems that modifications to $this aren't visible outside the method, creating a purely local clone, which would be discarded if it wasn't returned (or saved somewhere).

I can see the logic, but the result is a bit unintuitive:

data class Example {
   public function __construct(public int $x) {}
   public function inc(): void {
     $this->x++;
  }
}
$foo = new Example(0);
$foo->x++;
$foo->inc();
echo $foo->x; // 1, not 2


I think it would be clearer to prevent direct modification of $this:

data class Example {
   public function __construct(public int $x) {}
   public function inc(): void {
      $this->x++; // ERROR: Can not mutate $this in data class
   }
   public function withInc(): static {
      $new = $this; // explicitly make a local copy of $this
      $new->x++; // copy-on-write separates $new from $this
      return $new;
   }
}


That would still be compatible with Ilija's suggestion, which was to add special "mutating methods":

data class Example {
    public function __construct(public int $x) {}
    public mutating function inc(): void {
        $this->x++;
    }
}
$foo = new Example(0);
$foo->x++;
$foo->inc!(); // copy-on-write triggered *before* the method is called
echo $foo->x; // 2


--
Rowan Tommins
[IMSoP]

Reply via email to