rfc:nullsafe_calls

Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
rfc:nullsafe_calls [2014/12/03 23:49]
jwatzman
rfc:nullsafe_calls [2017/09/22 13:28] (current)
Line 1: Line 1:
 ====== PHP RFC: Nullsafe Calls ====== ====== PHP RFC: Nullsafe Calls ======
-  * Version: ​0.+  * Version: 1.0 
-  * Date: 2014-12-03+  * Date: 2014-12-09
   * Author: Josh Watzman (jwatzman@fb.com),​ Drew Paroski   * Author: Josh Watzman (jwatzman@fb.com),​ Drew Paroski
   * Status: Draft   * Status: Draft
Line 7: Line 7:
  
 ===== Introduction ===== ===== Introduction =====
 +**The RFC has been returned to draft stage after discussion on internals in order to figure out how to deal with short circuiting. See the "open issues"​ section below. The rest of the RFC currently stands as originally submitted to internals.**
 +
 This RFC proposes a new operator, the "​nullsafe"​ operator ''<​nowiki>?​-></​nowiki>'',​ which allows safe chaining of method calls. This is useful to easily propagate errors forward to the end of a computation which should fail if any of its sub-computations should fail. This RFC proposes a new operator, the "​nullsafe"​ operator ''<​nowiki>?​-></​nowiki>'',​ which allows safe chaining of method calls. This is useful to easily propagate errors forward to the end of a computation which should fail if any of its sub-computations should fail.
  
Line 58: Line 60:
 ==== Prior Art ==== ==== Prior Art ====
   * C#, CoffeeScript,​ and Groovy all have a "safe navigation operator"​ which was the original inspiration for this feature.   * C#, CoffeeScript,​ and Groovy all have a "safe navigation operator"​ which was the original inspiration for this feature.
 +  * Haskell has the "maybe monad",​ which syntactically looks quite different but morally provides a similar mechanism to propagate any failure in a computation forward to the end of the computation.
   * Hack has already implemented a proposal identical to this one.   * Hack has already implemented a proposal identical to this one.
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
-Due to an implementation detail, this decreases the maximum number of arguments a function can be called with from ''​2**32''​ to ''​2**31'',​ and adds an error when that limit is reached. (The engine would previously just wrap around, to potentially disastrous consequences.)+Due to an implementation detail, this decreases the maximum number of arguments a function can be called with from ''​2^32''​ to ''​2^31'',​ and adds an error when that limit is reached. (The engine would previously just wrap around, to potentially disastrous consequences.)
  
 This is just a technicality... all of my attempts to actually hit that limit put my machine into swapdeath long before I got close :-P This is just a technicality... all of my attempts to actually hit that limit put my machine into swapdeath long before I got close :-P
 +
 +See also "RFC Impact To Existing Extensions"​ below.
  
 ===== Proposed PHP Version(s) ===== ===== Proposed PHP Version(s) =====
Line 70: Line 75:
 ===== RFC Impact ===== ===== RFC Impact =====
 ==== To Existing Extensions ==== ==== To Existing Extensions ====
-Do extensions ​have access to the opline'​s ''​extended_value''​? If soat least with the current implementation, they will have to be updated to deal with one of the bits being used for a different ​purpose.+Extensions ​have access to an opline'​s ''​extended_value'', ​and the current implementation ​re-uses a single bit at the top of it for a new purpose. This is a backwards compatibility break for extensions which read the ''​extended_value''​ out of the "begin fcall" opcode -- though arguably extensions like RunKit which do this probably shouldn'​t be anyways ;) 
 + 
 +If this impact is deemed too much, there are certainly other implementation options, which I think are less attractive. We could add a new ''​OP_DATA''​ opcode after the begin fcall, but that seems like dramatic overkill for storing a single bit.
  
 ==== New Constants ==== ==== New Constants ====
Line 77: Line 84:
 ===== Open Issues ===== ===== Open Issues =====
 Make sure there are no open issues when the vote starts! Make sure there are no open issues when the vote starts!
 +
 +==== Short Circuit ====
 +The behavior for (not) short circuiting argued for above is not clearly the right behavior. There are actually at least //three// meaningful possibilities here. I'm currently investigating implementation feasibility in both PHP7 and in HHVM, as well as generally thinking about what the right thing to do is, and will bring the discussion back up on internals once I've got my thoughts together better.
 +
 +As a quick preview, the three options can be seen as to how to desugar the following code. I'm not going to argue for or against any of them yet, just show what the range of possibilities are. (I also haven'​t extensively looked at the following examples, they might have errors or just not make sense, I need more time to put this together properly, dumping here for completeness only, please wait for the full revised proposal to internals :))
 +
 +<PHP>
 +$r = $x?​->​a(f())->​b(g());​
 +</​PHP>​
 +
 +=== Option 1: no short circuit ===
 +Arguments are evaluated even if we are doing the nullsafe call on null.
 +
 +<PHP>
 +$_tmp1 = f();
 +$_tmp2 = g();
 +$_tmp3 = $x === null ? null : $x->​a($_tmp1);​
 +$r = $_tmp3->​b($_tmp2);​
 +</​PHP>​
 +
 +=== Option 2: one-level short circuit ===
 +Arguments are not evaluated if we are doing the nullsafe call on null. The nullsafe behavior only applies to the single function call where the nullsafe operator is used.
 +
 +<PHP>
 +$_tmp1 = $x === null ? null : $x->​a(f());​
 +$r = $_tmp1->​b(g());​
 +</​PHP>​
 +
 +=== Option 3: full short circuit ===
 +Arguments are not evaluated if we are doing the nullsafe call on null. The nullsafe behavior applies to all calls chained after the nullsafe operator.
 +
 +<PHP>
 +$r = $x === null ? null : $x->​a(f())->​b(g());​
 +</​PHP>​
  
 ===== Unaffected PHP Functionality ===== ===== Unaffected PHP Functionality =====
Line 88: Line 129:
  
 ===== Patches and Tests ===== ===== Patches and Tests =====
-  * php-src: I have a scratch ​branch at https://​github.com/​jwatzman/​php-src/​compare/​nullsafe-prototype?​expand=1 with a working implementation. ​As the RFC progresses, I plan to squash that down into a nicer PR for review+  * php-src: I have a branch at https://​github.com/​jwatzman/​php-src/​compare/​nullsafe-prototype?​expand=1 with a working implementation. ​Includes tests copied from HHVM's implementation
-  * PHP spec: nothing ​yet, but this shouldn'​t take too long.+  * PHP spec: not yet, but will do if the RFC is accepted.
   * PHP docs: import Hack's documentation when they add it: https://​github.com/​hhvm/​hack-hhvm-docs/​issues/​360 (that task will get completed well before this RFC is voted on, accepted, merged, etc)   * PHP docs: import Hack's documentation when they add it: https://​github.com/​hhvm/​hack-hhvm-docs/​issues/​360 (that task will get completed well before this RFC is voted on, accepted, merged, etc)
  
rfc/nullsafe_calls.1417650560.txt.gz · Last modified: 2017/09/22 13:28 (external edit)