rfc:increment_decrement_fixes
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
rfc:increment_decrement_fixes [2020/03/01 17:41] – created imsop | rfc:increment_decrement_fixes [2022/02/18 14:38] (current) – abandoned, because it brought all the trolls out of the woodwork, and life's too short imsop | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: Increment/ | ====== PHP RFC: Increment/ | ||
- | * Version: | + | * Version: |
- | * Date: 2020-03-01 | + | * Date: 2020-03-08 |
- | * Author: Rowan Tommins, rowan.collins@gmail.com | + | * Author: Rowan Tommins |
- | * Status: | + | * Status: |
* First Published at: http:// | * First Published at: http:// | ||
===== Introduction ===== | ===== Introduction ===== | ||
- | The increment and decrement operators (< | + | Intuitively, |
- | Intuitively, the <php>++</ | + | Most arithmetic operators, including |
- | This is currently not the case, as the table below shows: | + | On top of this, the < |
- | ^ Initial Value ^ %%$a = $a + 1%% ^ %%$a += 1%% ^ %%++$a%%, %%$a++%% ^ %%$a = $a - 1%% ^ %%$a -= 1%% ^ %%--$a%%, %%$a--%% ^ | + | ===== Fix or remove? ===== |
- | ^ 0 | 1 | 1 | 1 | -1 | -1 | -1 | | + | |
- | ^ null | 1 | 1 | 1 | -1 | -1 | null | | + | |
- | ^ true | 2 | 2 | true | 0 | 0 | true | | + | |
- | ^ false | 1 | 1 | false | -1 | -1 | false | | + | |
- | ^ array | Error | Error | silent | Error | Error | silent | | + | |
- | ^ object | 2 (+ Notice) | 2 (+ Notice) | unchanged | 0 (+ Notice) | 0 (+ Notice) | unchanged | | + | |
- | ^ resource#5 | 6 | 6 | resource#5 | 4 | 4 | resource #5 | | + | |
+ | A common concern is that fixing these inconsistencies would imply " | ||
- | The reason | + | The position of this RFC is that arithmetic operators should either be consistently allowed or consistently disallowed on a particular type. In particular, if <php>$a+=1</ |
+ | The balance of these factors is assessed for each type below, but in summary: | ||
- | ===== Proposal 1: Decrementing Null ===== | + | * For arrays, throw an error in 8.0, because most operators already do |
+ | * For objects, resources, and booleans, assume that an error will be proposed in a future RFC | ||
+ | * For null, continue to allow arithmetic operators, and fix the missing implementation of < | ||
- | The behaviour of null with < | + | ===== Strings ===== |
- | This behaviour has been raised as a bug at least three times ([[https:// | + | Strings overload the <php>++</php> and <php>--</php> operators with complex behaviour which mixes text and arithmetic logic. Improving this deserves its own discussion, so will not be discussed further |
- | Discrepancies in behaviour of null are particularly problematic, | + | ===== Arrays ===== |
- | This RFC proposes | + | Adding an integer |
- | ===== Proposal 2: Incrementing | + | This RFC proposes to change the behaviour so that < |
- | The behaviour of booleans | + | ^ ^ Initial Value ^ %%$a = $a + 1%% ^ %%$a += 1%% ^ %%++$a%%, %%$a++%% ^ %%$a = $a - 1%% ^ %%$a -= 1%% ^ %%--$a%%, %%$a--%% ^ |
+ | ^ Current ^ any array | Error | Error | no effect | Error | Error | no effect | | ||
+ | ^ Proposed ^ any array | Error | Error | Error | Error | Error | Error | | ||
+ | |||
+ | ===== Objects, resources, and booleans | ||
+ | |||
+ | Most arithmetic | ||
+ | |||
+ | * Objects (other than internal objects with operator overloading) are cast to 1, and an E_NOTICE | ||
+ | * Resources are cast to their internal ID | ||
+ | * false is cast to 0 | ||
+ | * true is cast to 1 | ||
+ | |||
+ | The < | ||
^ Initial Value ^ %%$a = $a + 1%% ^ %%$a += 1%% ^ %%++$a%%, %%$a++%% ^ %%$a = $a - 1%% ^ %%$a -= 1%% ^ %%--$a%%, %%$a--%% ^ | ^ Initial Value ^ %%$a = $a + 1%% ^ %%$a += 1%% ^ %%++$a%%, %%$a++%% ^ %%$a = $a - 1%% ^ %%$a -= 1%% ^ %%--$a%%, %%$a--%% ^ | ||
- | ^ true | 2 | 2 | true | 0 | 0 | true | | + | ^ any object |
+ | ^ resource#1 | 2 | 2 | no effect | 0 | 0 | no effect | | ||
+ | ^ resource#5 | 6 | 6 | no effect | 4 | 4 | no effect | ||
^ false | 1 | 1 | false | -1 | -1 | false | | ^ false | 1 | 1 | false | -1 | -1 | false | | ||
+ | ^ true | 2 | 2 | true | 0 | 0 | true | | ||
- | This RFC proposes to change the behaviour so that it is in line with other mathematical contexts, giving this: | + | Possible options: |
- | ^ Initial Value ^ %%$a = $a + 1%% ^ %%$a += 1%% ^ %%++$a%%, %%$a++%% ^ %%$a = $a - 1%% ^ %%$a -= 1%% ^ %%--$a%%, %%$a--%% ^ | + | * A: Implement < |
- | ^ true | 2 | 2 | 2 | 0 | 0 | 0 | | + | * B: Raise an error for < |
- | ^ false | 1 | 1 | 1 | -1 | -1 | -1 | | + | * C: Raise an error for all arithmetic operators. |
+ | |||
+ | The position of this RFC is that option A brings very little benefit for these types, because the resulting values aren't particularly intuitive or useful. On the other hand, option B simply swaps one inconsistency for another. Option C has the added benefit of bringing the behaviour of these types in line with the behaviour of arrays. | ||
+ | |||
+ | The implications of introducing such an error deserve their own RFC. For instance, it was mentioned in [[rfc/ | ||
+ | |||
+ | The position of this RFC is to leave these types unchanged, in the expectation of a further RFC implementing option C. | ||
+ | |||
+ | ===== Null ===== | ||
+ | |||
+ | Nulls deserve special consideration for two reasons: | ||
+ | |||
+ | * The implicit coercion to int is significantly more useful than for other types | ||
+ | * The <php>++</ | ||
+ | |||
+ | ==== Current inconsistency ==== | ||
+ | |||
+ | For nearly all arithmetic operators, < | ||
+ | |||
+ | This behaviour has been raised as a bug at least three times ([[https:// | ||
+ | |||
+ | Consider the following patch, which looks like a straight-forward simplification: | ||
+ | |||
+ | <code diff> | ||
+ | function foo($bar) { | ||
+ | - $bar -= 1; | ||
+ | + | ||
+ | // more code here | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | The old code always results in an integer in <php>$bar</ | ||
+ | |||
+ | The asymmetry of <php>++</ | ||
+ | |||
+ | <code diff> | ||
+ | function repeatThing($extraTimes) { | ||
+ | - for ( $i = 0; $i <= $extraTimes; | ||
+ | + for ( $i = $extraTimes; | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Again, this looks like a safe change, reversing the order of the loop; but if passed | ||
+ | |||
+ | ==== Options ==== | ||
+ | |||
+ | There are four main options to improve the situation: | ||
+ | |||
+ | * A: Implement < | ||
+ | * B1: Raise an error for < | ||
+ | * B2: Raise an error for both < | ||
+ | * C: Raise an error for all arithmetic operators. | ||
+ | |||
+ | Option B1 is in some ways the safest, because it makes the change immediately visible, and most cases affected are probably already buggy. However, it is hard to justify raising an error for <php>$a--</ | ||
+ | |||
+ | ==== Removing null to int coercion ==== | ||
+ | |||
+ | Should we then go with Option C, as proposed for other types? That is, should we introduce, either immediately, | ||
+ | |||
+ | An important consideration is that undefined variables, array items, and object properties are currently treated as having a value of null. While it has been suggested to change this to an error in a future version, there is no clear consensus to do so. This means operations on null are more common than the other types we have discussed, and are likely to remain so. | ||
+ | |||
+ | Furthermore, | ||
+ | |||
+ | Even the increment operator itself can be useful with null / unitialised values, for instance in this common implementation of "count items in each category": | ||
+ | |||
+ | <code php> | ||
+ | $counts = []; | ||
+ | foreach ( $items as $item ) { | ||
+ | $counts[$item-> | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | If there was no implicit default of zero, an extra line such as < | ||
+ | |||
+ | Since the case for removing null to int coercion is much less decisive than for other types, this RFC makes the assumption that no such removal is likely in the short term. As such, waiting for that removal does not solve the immediate problem of inconsistency between < | ||
+ | |||
+ | ==== Fixing the decrement case ==== | ||
+ | |||
+ | As mentioned above, no evidence has been put forward that the missing definition of decrement for null is intentional. | ||
+ | |||
+ | This RFC therefore proposes to fix this bug, so that < | ||
+ | ^ ^ Initial Value ^ %%$a = $a + 1%% ^ %%$a += 1%% ^ %%++$a%%, %%$a++%% ^ %%$a = $a - 1%% ^ %%$a -= 1%% ^ %%--$a%%, %%$a--%% ^ | ||
+ | ^ Current ^ null | 1 | 1 | 1 | -1 | -1 | null | | ||
+ | ^ Proposed ^ null | 1 | 1 | 1 | -1 | -1 | -1 | | ||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
- | The proposed changes to null and boolean handling are not backwards compatible. The current behaviour | + | The additional error on increment |
+ | The fix to decrement on nulls is harder to detect. While it's unlikely that any code is deliberately relying on the current behaviour, it may inadvertently be doing so. It would be sensible to provide links in official upgrading documentation to static analysis tools which can point out potentially affected code. | ||
===== Proposed PHP Version(s) ===== | ===== Proposed PHP Version(s) ===== | ||
Line 64: | Line 163: | ||
===== RFC Impact ===== | ===== RFC Impact ===== | ||
+ | |||
+ | ==== On OpCache ==== | ||
+ | |||
+ | If there is currently any optimisation based on the non-implementation of decrement for nulls, or the behaviour of increment and decrement for arrays, this will need to be amended if the respective votes pass. | ||
===== Open Issues ===== | ===== Open Issues ===== | ||
- | objects, arrays, resources... | + | None at time of initial discussion. |
===== Unaffected PHP Functionality ===== | ===== Unaffected PHP Functionality ===== | ||
- | * Undefined variables, array items, and object properties are currently treated as null for most purposes, including the < | + | As mentioned above, this RFC proposed no changes to handling |
- | * Similarly, most mathematical contexts will coerce null and false to 0, and true to 1; this RFC does not seek to change | + | |
- | * Strings overload the < | + | It also does not directly propose |
===== Proposed Voting Choices ===== | ===== Proposed Voting Choices ===== | ||
- | * Should decrementing null result | + | The two proposed changes can be implemented independently, |
- | * Should incrementing | + | |
+ | | ||
+ | * Should incrementing | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
- | TODO | + | None yet. The implementation should be a simple addition to the '' |
===== Implementation ===== | ===== Implementation ===== | ||
Line 93: | Line 198: | ||
===== References ===== | ===== References ===== | ||
- | * [[https:// | + | |
- | * [[https:// | + | * [[https:// |
- | * [[https:// | + | * [[https:// |
===== Rejected Features ===== | ===== Rejected Features ===== | ||
- | TODO | + | A previous version of the RFC proposed fixing the implementation for booleans to match integer coercion followed by adding or substracting 1. The current draft instead groups booleans with objects and resources, as warranting a separate RFC proposing an error. |
rfc/increment_decrement_fixes.1583084492.txt.gz · Last modified: 2020/03/01 17:41 by imsop