-
Notifications
You must be signed in to change notification settings - Fork 2.8k
[PSR-7] Clarify requirement for new instances #482
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
[PSR-7] Clarify requirement for new instances #482
Conversation
|
👍 @pmjones if you can merge this, awesome. |
|
-1 from me. This seems like a pointless requirement.
Why prohibit this if it is a micro-optimization? Where did you come up with the idea that it is an edge case? I feel like this claim cannot be backed up.
This is the same point as above, which I don't think is valid. What is the reasoning of preventing a micro-optimization?
What's the use case here? I see no reason to compare with strict equality on these value objects. The aggregate of the values stored in the object is the value -- the value is not based on whether or not the result of Differences between implementations as to whether or not they clone always or conditionally does not affect their usage of the interfaces. It's an implementation detail and shouldn't matter to the end user. |
|
@mtdowling TBH, I could go either way. :) The "uniformity of return value" is an important argument when designing interfaces, as it reduces ambiguity. On the flip side, modeling as a value object means that if two objects are equivalent, they're also interchangeable. I'm open to changing the verbiage on this to allow |
|
@mtdowling This reasoning is being added to the spec to back up why the spec currently requires it. That was the original way the spec was written. If the spec stays the way it is now, we need to have this. The alternative is to change the spec to remove the requirement of returning a new instance. I believe that is still on the table as well. Now that we are in review we can revisit that. The big issue with the spec as it was is that it was written in such a way that people were implementing it counter to the spec (returning $this as a micro-optimization). |
|
Gotcha. I see that the docblocks say that it always returns a clone. Perhaps it could be updated to say something along the lines of "returns a clone of the object or implementations may choose to return the same instance if the value is not modified as a result of calling the with method". Any sort of language that states that values MUST be cloned could be a slippery slope.. For example, if a request MUST be cloned, then should the URI instance and stream owned by the request be cloned as well, or is it ok to use a reference here instead? |
|
@mtdowling Yep, that was one of the things that has come up in the last week or so. Everyone saw it and was cool with it and then implemented it differently. :) I think that the point of the docblock was to convey the "spirit of immutability" by returning a new object. However, that is an implementation detail. Personally, I think we could just remove "and return a new instance that contains the changed state" and call it good.
I think this would allow for both returning a clone along with this, as long as the protocol version passed in was the protocol version that the object had originally (since the returned object would have the desired protocol version). But maybe it isn't explicit enough. |
|
Let me know what the final story is on this. |
|
@mtdowling Here's a draft of a revised Essentially, it changes "a new instance" to "new instance", and "Creates a new instance" to "Returns an instance" throughout. This should allow for either |
|
Awesome! I think that is the best way to address the issue. |
This patch alters the previous clarification to flip and explicitly allow `return $this` if the values are equivalent.
|
@mtdowling and @simensen : I've updated the patch to explicitly allow |
|
🚢 |
|
Cannot "an instance" mean "this instance, even with changed values" ? I like the clarity of "a new instance" every time -- it nothing else it's consistent. I fail to see the true harm of that wording preventing a micro-optization. |
|
@pmjones the text prior to "an instance" is "preserve immutability". You cannot change the current instance AND preserve immutability. However, if no change is made, you're still preserving immutability, even if the same instance is returned. Also, I'd not considered this, but consumers such as ReactPHP and Guzzle are cases where the same values may be set again and again. In those cases, the proposed changes would have a performance impact, as they could potentially eliminate the needs for dozens or hundreds of additional instances. |
Ah so; I concentrated on the red/green. I am satisfied. |
|
At an interface level this may be dangerous, because of copy-on-write semantics. Especially if you're getting/setting array and object values. As they may appear equal (pass I'm not saying it's not worth doing, just pointing out that there's non-trivial edge-case complications associated with this edge-case. |
|
@ircmaxell the issue is that the way it was written previously would mean that returning the same instance when no change was needed would be invalid according to the spec. There is no reason for the spec to forbid it IMO, as long as the implementation respects immutability. |
|
@ircmaxell and @stof : the salient points for allowing either case are:
Essentially, we have to weigh the edge cases we want to address here. Based on playing with PSR-7 in applications already, I can note that comparison of two instances is rare, while spawning new instances is rampant, and, as such, I think it makes sense to address the latter. |
|
@weierophinney My point was more around detecting when a change happened via Perhaps better would be to simply specify the interface as immutable, and let implementations determine when to |
That's actually quite similar to the language this patch proposes:
The above is the general language in the various |
|
👍 |
|
👍 much clearer |
|
👍 |
1 similar comment
|
👍 |
[PSR-7] Clarify requirement for new instances
An "optimization" suggested on several occasions is to
return $this;fromwith*()methods if the argument presented is equal to the current value in the object. However, the specification indicates a new instance MUST be returned.This patch provides verbiage indicating why the behavior indicated in the specification was chosen (to remove ambiguity with regards to the return value).Updated: This patch provides verbiage indicating that
return $thisis explicitly allowed if the instances are equivalent in value.