rfc:default_expression

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:default_expression [2024/08/28 22:35] bilgerfc:default_expression [2024/08/29 21:46] (current) – Added two seconary discussion concerns bilge
Line 103: Line 103:
 <code php> <code php>
 $f = fn ($v = 1, $default = 2) => $v + $default; $f = fn ($v = 1, $default = 2) => $v + $default;
-var_dump($f(default: default + 1)); // int(4)+$f(default: default + 1); // int(4)
 </code> </code>
  
Line 138: Line 138:
  
 Currently the only known failure case is lookup of trampoline functions, which can be created by calling <php>__invoke</php> on a closure, as in <php>(fn ($P = 1) => $P)->__invoke(default);</php>. Considering this is not the intended, nor even a documented way of invoking a closure, it is supposed this limitation is very minor. Currently the only known failure case is lookup of trampoline functions, which can be created by calling <php>__invoke</php> on a closure, as in <php>(fn ($P = 1) => $P)->__invoke(default);</php>. Considering this is not the intended, nor even a documented way of invoking a closure, it is supposed this limitation is very minor.
 +
 +===== Discussion =====
 +
 +The greatest concern is the proposed grammar is too permissive and has drawbacks. Secondary concerns include evaluating <php>default</php> in the calling context, and default values are now part of an object's public API. We will examine each of these issues in detail.
 +
 +==== Limiting grammar ====
 +
 +The most common request is to constrain the allowed expression list. As already noted, some expressions don't make much sense because they probably don't have any practical application, and some are not comfortable allowing expressions that don't make sense into the language. This implies coming up with an [[https://externals.io/message/125183#125218|arbitrary exclusion list]] for certain expressions. Some proposed taking this a step further by [[https://externals.io/message/125183#125321|disallowing default as expression input]], which effectively rules out all operator classes except conditionals and invocations of <php>match()</php> that use <php>default</php> as a stand-alone output token.
 +
 +<code php>
 +// Expressions with default as output only.
 +F(1 ? default : 0)
 +F(1 ? 1 : default)
 +F(0 ?: default)
 +F(null ?? default)
 +F(match(1) { 1 => default })
 +</code>
 +
 +Further, some even expressed concerns about allowing any expressions at all and would only be comfortable allowing <php>default</php> as an isolated token, as in [[skipparams]].
 +
 +Critics converged on a [[https://externals.io/message/125183#125274|valid counter-point]] that permitting expressions changing the default's type breaks LSP, as demonstrated in the following example (code courtesy of Ilija). Some have suggested this might be solved by disallowing <php>default</php> to be passed to union types (including <php>mixed</php>).
 +
 +<code php>
 +class C {
 +    public function F(int $V = 1) {}
 +}
 +
 +class D extends C {
 +    public function F(int|string $V = 's') {}
 +}
 +
 +function test(C $C) {
 +    $C->F(default + 1);
 +}
 +
 +test(new C); // OK.
 +test(new D); // Fatal error: Uncaught TypeError: Unsupported operand types: string + int.
 +</code>
 +
 +==== Default as a dummy value ====
 +
 +Currently <php>default</php>, as described by this RFC, is effectively replaced by the callee's default value and then passed to the callee from the caller, meaning the caller has full access to the default value. Some have [[https://externals.io/message/125183#125265|argued]] for an implementation that more literally follows the premise of this RFC, which is that <php>default</php> is just a dumb token that is standing in for //nothing//; it does not represent any value to the caller and merely instructs the callee to use its default value in the same way as when not passing the argument.
 +
 +==== Defaults as a contract ====
 +
 +Some have argued allowing <php>default</php> to read argument default values, previously only accessible via reflection, suddenly makes defaults part of an object's published API. However, changing a default is a behavioural change for any caller previously relying on those defaults (by not passing any argument), ergo defaults have always been part of the published API.
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
Line 156: Line 202:
 </doodle> </doodle>
  
-Regardless of how you vote above, we'd like to collect feedback on which limitations of this proposal would make it/still be acceptable for you, starting from the least significant to the most drastic changes. For details on what each of these options mean, see [[#discussion|discussion]]. You can vote for multiple options, but if you choose the last one then it doesn't make much sense to pick any others.+Regardless of how you vote above, we'd like to collect feedback on which limitations of this proposal would make it/still be acceptable for you, starting from the least significant to the most significant changes. For details on what each of these options mean, see [[#discussion|discussion]]. You can vote for multiple options, but if you choose the last one then it doesn't make much sense to pick any others.
  
-<doodle title="Which limited variations would you support?" auth="bilge" voteType="multi" closed="false" closeon="2024-08-09T21:00:00Z">+<doodle title="Which limited grammars would you support?" auth="bilge" voteType="multi" closed="false" closeon="2024-08-09T21:00:00Z">
    * No union types    * No union types
    * Only conditional expressions    * Only conditional expressions
Line 165: Line 211:
 </doodle> </doodle>
  
-Only the result of the primary vote has a clear path forward for default arguments to be included in PHPIf the primary vote fails, the secondary vote may inform whomsoever wishes to pursue a follow-up for limited defaultsbut that would require someone to write brand new RFC and implementation for that counter-proposal.+Only the result of the primary vote has a clear path forward for inclusion into the languageNone of the proposed alternatives come with any feasibility guarantees. However, if the primary vote fails, the secondary vote may inform whomsoever wishes to pursue a follow-up for limited application of ''default''which requires a new RFC and implementation for that counter-proposal.
  
 ===== Appendix I: Further examples ===== ===== Appendix I: Further examples =====
Line 259: Line 305:
 // Match // Match
 F(match(default) { default => default }) F(match(default) { default => default })
 +
 +// Callable
 +F((default)->M())
  
 // Parens // Parens
Line 276: Line 325:
 F(print default) F(print default)
 </code> </code>
- 
-===== Discussion ===== 
- 
-The biggest concern is the proposed grammar is too permissive and has drawbacks. A secondary concern is default values are now part of an object's public API. We will examine each of these issues in detail. 
- 
-==== Limiting grammar ==== 
- 
-The most common request is to constrain the allowed expression list. As already noted, some expressions don't make much sense because they probably don't have any practical application, and some are not comfortable allowing expressions that don't make sense into the language. This implies coming up with an [[https://externals.io/message/125183#125218|arbitrary exclusion list]] for certain expressions. Some proposed taking this a step further by [[https://externals.io/message/125183#125321|disallowing default as expression input]], which effectively rules out all operator classes except conditionals and invocations of <php>match()</php> that use <php>default</php> as a stand-alone output token. 
- 
-<code php> 
-// Expressions with default as output only. 
-F(1 ? default : 0) 
-F(1 ? 1 : default) 
-F(0 ?: default) 
-F(null ?? default) 
-F(match(1) { 1 => default }) 
-</code> 
- 
-Further, some even expressed concerns about allowing any expressions at all and would only be comfortable allowing <php>default</php> as an isolated token, as in [[skipparams]]. 
- 
-Critics converged on a [[https://externals.io/message/125183#125274|valid counter-point]] that permitting expressions changing the default's type breaks LSP, as demonstrated in the following example (code courtesy of Ilija). This might be solved by disallowing <php>default</php> to be passed to union types. 
- 
-<code php> 
-class C { 
-    public function F(int $V = 1) {} 
-} 
- 
-class D extends C { 
-    public function F(int|string $V = 's') {} 
-} 
- 
-function test(C $C) { 
-    $C->F(default + 1); 
-} 
- 
-test(new C); // OK. 
-test(new D); // Fatal error: Uncaught TypeError: Unsupported operand types: string + int. 
-</code> 
- 
-==== Defaults as a contract ==== 
- 
- 
  
 ===== References ===== ===== References =====
rfc/default_expression.1724884513.txt.gz · Last modified: 2024/08/28 22:35 by bilge