Open kkmuffme opened 1 year ago
I found these snippets:
That's something I never completely understood in Psalm.
Which symbols are allowed to be called pure/immutable/mutation-free/external-mutation-free, which of these denominations can be used in a symbol that has another denomination etc...
We miss a big documentation on that and it's a pain to work with.
I think if we wanted to add what you want, a @psalm-all-method-pure would maybe be more clear. I'm afraid adding @psalm-pure
to a class would add to the confusion and make people think a class can actually be pure (which by the way, I have no idea if that could be a thing and what should be checked in order to enforce that...)
For me @psalm-immutable
is pretty weird.
When I met him as first time, I thought that he makes all the properties of the class as readonly.
My surprise was indescribable when I realized that this annotation also applies to methods: https://psalm.dev/r/987df51c8b
Why is another annotation needed?
We're going to fix @psalm-immutable
?
I found these snippets:
My surprise was indescribable
Same for me, when I realized this a few days ago. So basically @psalm-immutable is kind of like @psalm-pure for classes already anyway? Except that the methods aren't marked as pure leading to complete inconsistency?
Except that the methods aren't marked as pure leading to complete inconsistency?
I don't like it. This leads to strange edge cases: https://psalm.dev/r/933c984ea0
In my opinion, @psalm-immutable
should be about only immutability.
i.e. @psalm-immutable
= @psalm-readonly
for all properties.
/**
* @psalm-immutable
*/
final class Foo
{
public function __construct(
public int $a,
public string $b,
) {}
}
final class Foo
{
public function __construct(
/** @psalm-readonly */
public int $a,
/** @psalm-readonly */
public string $b,
) {}
}
I found these snippets:
In my opinion, @psalm-immutable should be about only immutability.
Exactly.
I would recommend giving this blog post a read: https://psalm.dev/articles/immutability-and-beyond
In my opinion,
@psalm-immutable
should be about only immutability. i.e.@psalm-immutable
=@psalm-readonly
for all properties.
Let me try to change your minds by giving this example: https://psalm.dev/r/9612ecfbc7
Adding the @psalm-immutable
annotation will catch the 'error'.
It is really hard to define what immutability and purity mean in an object oriented context.
I found these snippets:
Adding the @psalm-immutable annotation will catch the 'error'.
What 'error'? I don't quite understand. You have put a reference to the mutable data structure in to the immutable data structure. What are you expecting? It data structure can change at any time. But reference inside immutable data structure will ever point to the same object.
I found these snippets:
You have put a reference to the mutable data structure in to the immutable data structure. What are you expecting?
I expect an object which is called immutable to not change its state. For me, this includes all of the states of all inner objects (recursively), not just the data (in this case a reference / pointer to some other object) directly inside the immutable object.
So IMO the example you gave should throw some error related to the change of the inner state (...->bar = 321;
) similar to how psalm handles this with arrays: https://psalm.dev/r/912c1c1cdf
I found these snippets:
I expect an object which is called immutable to not change its state. For me, this includes all of the states of all inner objects (recursively), not just the data (in this case a reference / pointer to some other object) directly inside the immutable object.
How? https://psalm.dev/r/6b6a329212
You can have many many other referenses to stdClass
comes from anywhere.
Where is guarantie that owner does not mutate stdClass
that was passed to the immutable class?
The most reasonable thing we can do is prohibit to pass mutable type to the immutable type.
<?php
final class Mutable
{
public function __construct(
public string $value,
) {
}
}
/**
* @psalm-immutable
*/
final class Immutable
{
public function __construct(
// This should be an error!
public Mutable $value,
) {
}
}
I found these snippets:
See #5441 I even forgot that it used to be. But for some reason this issue was ignored (
See #6881 similar issue
@ygottschalk your example is wrong (I saw you do the same thing before), but this is not a valid syntax. When you do the example correctly: https://psalm.dev/r/a1981ffdc7
It is reported even without @psalm-immutable.
I found these snippets:
@kkmuffme My first given example copy-pasted to some sandbox: https://3v4l.org/IfpNO#v8.2.7
When you do the example correctly: [...]
Let me correct your "correction": https://psalm.dev/r/29a298f5a3 - No errors
It is reported even without @psalm-immutable.
I was talking about an ImpurePropertyAssignment
error, not some TooManyArguments
or PropertyNotSetInConstructor
I found these snippets:
@klimick Reading your post I was like "Wasn't that an issue I worked around someday..?" but reading on I saw you actually found that.
How?
I was just trying to explain what my general understanding / interpretation of an 'immutable object' is. I am aware that it is (near) impossible to enforce that. Even if we would require a deep clone which would be guaranteed to not have any references elsewhere, you could easily use the Reflection API to access and change that.
https://psalm.dev/r/b3282d3d68
Sometimes (e.g. utility classes) you want to enforce that it only contains pure methods, allowing @psalm-pure on the class (like @psalm-immutable) would be nice. Additionally this would declaring @psalm-pure on each method obsolete then (like @psalm-mutation-free isn't necessary on methods in @psalm-immutable)