rfc:structs-v2
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:structs-v2 [2024/04/23 15:50] – Reflection ilutov | rfc:structs-v2 [2024/04/24 20:33] (current) – ilutov | ||
---|---|---|---|
Line 33: | Line 33: | ||
===== The problem ===== | ===== The problem ===== | ||
- | Classes are commonly used to model data in PHP. Such classes have many names (data transfer objects, plain old php objects, records, etc.). This allows the developer to describe the shape of the data, thus documenting it and improving developer experience in IDEs. | + | Classes are commonly used to model data in PHP. Such classes have many names (data transfer objects, plain old php objects, records, etc.). This allows the developer to describe the shape of the data, thus documenting it and improving developer experience in IDEs over arrays. |
Using classes for data comes with one significant downside: Objects are passed by reference, rather than by value. When dealing with mutable data, this makes it very easy to shoot yourself in the foot by exposing mutations to places that don't expect to see them. | Using classes for data comes with one significant downside: Objects are passed by reference, rather than by value. When dealing with mutable data, this makes it very easy to shoot yourself in the foot by exposing mutations to places that don't expect to see them. | ||
Line 57: | Line 57: | ||
$shapes = createShapes(); | $shapes = createShapes(); | ||
- | function applyGravity() { | + | // Apply gravity |
- | foreach ($shapes as $shape) { | + | |
- | | + | |
- | $shape-> | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | applyGravity($shape); | + | |
foreach ($shapes as $shape) { | foreach ($shapes as $shape) { | ||
+ | /* We're not physicists. :P */ | ||
+ | $shape-> | ||
var_dump($shape-> | var_dump($shape-> | ||
} | } | ||
Line 95: | Line 89: | ||
// | // | ||
+ | |||
+ | At first glance, it doesn' | ||
====== Growable data structures ====== | ====== Growable data structures ====== | ||
Line 161: | Line 157: | ||
===== CoW 🐄 ===== | ===== CoW 🐄 ===== | ||
- | But wait, this sounds familiar. | + | But wait: |
< | < | ||
What's the solution? '' | What's the solution? '' | ||
+ | |||
+ | ... | ||
+ | |||
+ | Like arrays, strings and other value types, structs are // | ||
< | < | ||
</ | </ | ||
- | You may assume that structs come with the same slowdown as creating a copy for each assignment of an object. However, structs have a cool trick up their sleeves: Copy-on-write, | + | This solution doesn' |
<code php> | <code php> | ||
Line 276: | Line 276: | ||
Only mutating methods can and must be called using the '' | Only mutating methods can and must be called using the '' | ||
+ | |||
+ | Similarly, classes trying to implement '' | ||
TOOD: Check if we can enforce '' | TOOD: Check if we can enforce '' | ||
Line 312: | Line 314: | ||
} | } | ||
- | $vector = new Vector([[1], | + | $vector = new Vector([[1], |
$vector-> | $vector-> | ||
</ | </ | ||
Line 337: | Line 339: | ||
TODO: This is actually broken currently. | TODO: This is actually broken currently. | ||
- | This modification is //not// considered mutating, because the object may change from some other place anyway. Structs behave closer to objects, so interior mutation is not allowed. | + | This modification is //not// considered mutating, because the object may change from some other place anyway. Structs behave closer to arrays, so interior mutation is not allowed. |
<code php> | <code php> | ||
Line 350: | Line 352: | ||
<code php> | <code php> | ||
$bigNum1 = new BigNum(1); | $bigNum1 = new BigNum(1); | ||
- | $bigNum2 = new BigNum(1); | + | $bigNum2 = $bigNum1; |
$reflection = new ReflectionProperty(BigNum:: | $reflection = new ReflectionProperty(BigNum:: | ||
- | $reflection-> | + | $reflection-> |
+ | |||
+ | // Desired behavior | ||
+ | var_dump($bigNum1, | ||
</ | </ | ||
- | To work properly, '' | + | for this to work properly, '' |
For this reason, I have opted to throw when passing a struct object to '' | For this reason, I have opted to throw when passing a struct object to '' | ||
Line 363: | Line 368: | ||
Inheritance is currently not allowed for structs. Structs are mainly targeted at data modelling, which should prefer composition over inheritance. There are currently no known technical issues with inheritance for structs, but we may want to be cautious when introducing them, and carefully consider the plethora of subtle semantic nuances. | Inheritance is currently not allowed for structs. Structs are mainly targeted at data modelling, which should prefer composition over inheritance. There are currently no known technical issues with inheritance for structs, but we may want to be cautious when introducing them, and carefully consider the plethora of subtle semantic nuances. | ||
+ | |||
+ | Implementing interfaces is allowed, however. Interface methods may be '' | ||
+ | |||
+ | ===== Hashing ===== | ||
+ | |||
+ | '' | ||
+ | |||
+ | ===== Move semantics ===== | ||
+ | |||
+ | There are still some cases where useless copies occur. | ||
+ | |||
+ | <code php> | ||
+ | function doubled($bigNum) { | ||
+ | $bigNum-> | ||
+ | return $bigNum; | ||
+ | } | ||
+ | |||
+ | $bigNum = 1; | ||
+ | $bigNum = doubled($bigNum); | ||
+ | </ | ||
+ | |||
+ | In this case, copying '' | ||
+ | |||
+ | One could implement such move semantics by hand. | ||
+ | |||
+ | <code php> | ||
+ | function move(& | ||
+ | $moved = $value; | ||
+ | $value = null; | ||
+ | return $moved; | ||
+ | } | ||
+ | |||
+ | $bigNum = 1; | ||
+ | $bigNum = doubled(move($bigNum)); | ||
+ | </ | ||
+ | |||
+ | Essentially, | ||
+ | |||
+ | There were some attempts to implement implicit move semantics, namely https:// | ||
===== Performance ===== | ===== Performance ===== | ||
- | TODO | + | Assignment to a property now needs to check whether the object is a struct object, and then clone it. This change was necessary in various code paths. In my benchmarks, this lead to a small slowdown of +0.07%, whether you use structs or not. The benchmark was performed on Symfony Demo, with Opcache. |
===== Backwards incompatible changes ===== | ===== Backwards incompatible changes ===== | ||
- | TODO | + | '' |
- | + | ||
- | ===== Future scope ===== | + | |
- | - Hashing for '' | + | There are no other backwards incompatible changes. |
===== Vote ===== | ===== Vote ===== |
rfc/structs-v2.1713887405.txt.gz · Last modified: 2024/04/23 15:50 by ilutov