Hi Bob, On Tue, Aug 20, 2024 at 12:18 AM Bob Weinand <bobw...@hotmail.com> wrote: > The fluid Arrays section says "A PoC has been implemented, but the > performance impact is still uncertain". Where may I find that PoC for my > curiosity? I'm imagining the implementation of the array types as a counted > collection of types of the entries. But without the PoC I may only guess.
I may publish the PoC at some point, but in the meantime here is a short description of how it's implemented: - The zend_array has a zend_type member representing the type of its elements - Everytime we add or update a member, we union its type with the array type. For simple types it's just a |= operation. For arrays with a single class it's also simple. For complex types it's more expensive currently, but it may be possible to cache transitions to make this cheaper. - Updating the array type on deletes requires to either maintain a counter of every type, or to re-compute the type entirely everytime. Both are probably too expensive. Instead, we don't update the type on deletes, but we re-compute the type entirely when a type check fails. This is based on two hypotheses: 1. A delete rarely changes an array's type in practice, and 2. Type checks rarely fail - References are treated as mixed, so adding a reference to an array or taking a reference to an element changes its type to mixed. Passing an array<mixed> to a more specific array<something> will cause a re-compute, which also de-refs every reference. - Updating a nested element requires updating the type of every parent > It also says "Another issue is that [...] typed properties may not be > possible.". Why would that be the case? Essentially a typed property would > just be a static array, which you describe in the section right below. It becomes complicated when arrays contain references or nested arrays. Type constraints must be propagated to nested arrays, but also removed when an array is not reachable via a typed property anymore. E.g. class C { public array<array<int>> $prop; } $a = &$c->prop[0]; $a[] = 'string'; // must be an error unset($c->prop[0]); $a[] = 'string'; // must be accepted $b = &$c->prop[1]; $b[] = 'string'; // must be an error $c->prop = []; $a[] = 'string'; // must be accepted I don't remember all the possible cases, but I didn't find a way to support this that didn't involve recursively scanning an array at some point. IIRC, without references it's less of an issue, so a possible way forward would be to forbid references to members of typed properties. Unfortunately this breaks pass-by-reference, e.g. `sort($c->prop)`. out/inout parameters may be part of a solution, but with more array separations than pass-by-ref. Best Regards, Arnaud