On Mon, Jul 19, 2021 at 10:41 AM Nicolas Grekas <nicolas.gre...@gmail.com> wrote:
> Hi all, > > I want to bring your attention to a behavior that was mostly overlooked: > > 1. it is not possible to use an intersection type with an argument that > defaults to null > 2. it is not possible to use an intersection type with a nullable > property (nor to make it default to null) > 3. it is not possible to use an intersection type with a nullable return > type > > Actually, 2. was possible until it was "closed" in > https://github.com/php/php-src/pull/7254 > > I reported these behavior and you might find some discussion about it in > https://bugs.php.net/81268 > > Looking at the past discussion on this list ( > https://externals.io/message/113712) and at the rfc itself ( > https://wiki.php.net/rfc/pure-intersection-types), this was mostly > overlooked. > > That's why I'm posting this message. So that we can have that missing > discussion here. > > To me, we are going to need (userland "we") these capabilities. > > It's quite surprising to be "forced" to return something, or "forced" to > pass a value, when all other types in PHP allow "null". I know about the > null pattern, but it is quite uncommon in PHP, because "null" works just > great usually. > > I feel like we "just" need to agree on a syntax to make this possible. It > was first suggested in the related PR to use "?A&B" (see > https://github.com/php/php-src/pull/6799#issuecomment-804761117) > > This was rejected by the author with the reasoning that (?A)&B could mean > (?A)&B or ?(A&B) or even (?A)|B. > > I personally don't think this ambiguity exists: (?A)|B is strictly the same > as A&B, thus ?A&B cannot also mean A&B, and I don't get how one could take > ?A&B for (?A)|B. > To me, the `|` (instead of `&`) in the original "is it `(?A)|B` or `?(A&B)`" was just a blatant typo. By the way, I think you made a couple of typos yourself: - "Actually, 2. was possible until [GitHub PR 7254]": 2. wasn't possible (as shown in bugsnet #81268), I guess you meant 1. (i.e. https://github.com/php/php-src/pull/7254/commits/710332aec7adf0f729b927d6bb7ae33c38703ce7 ) - "(?A)|B is strictly the same as A&B": looks like you copy-pasted the original typo ;) Indeed, `(?A)&B`, i.e. `(null|A)&B` (currently both unsupported syntaxes), is necessarily the same as just `A&B`. As for supporting the `?A&B` syntax, several issues were raised: - Ambiguity: We would want the `?` "unary operator" to have a "lower precedence" than the `&` "binary operator" (like `null|A&B` or explicit `null|(A&B)`), which would be the opposite of familiar `!A&B` for "true" operators. There was also some opposition to "implicit precedence" / preference for requiring explicit grouping. - Inconsistency: The similar `?A|B` syntax was explicitly rejected when introducing union types. Moreover the future scope anticipates full composite types, allowing arbitrary `A&B|C` (or `(A&B)|C`). And the main obstacle to supporting general composite types (whatever the syntax): Unknown variance/LSP correctness (apparently complex to specify/implement): George expressed themself in https://wiki.php.net/rfc/pure-intersection-types#composite_types_ie_mixing_union_and_intersection_types : > While early prototyping shows that supporting A&B|C without any grouping looks feasible, there are still many other considerations (e.g. Reflection), but namely the variance rules and checks, which would be dramatically increased and prone to error. and in https://github.com/php/php-src/pull/6799#issuecomment-805452895 : > the issue is less about parsing nor type checking (as my initial prototype shows although far from done), but the variance rules and checks, it already needs a different nested loop order to traverse both the parent and the child type list just for the pure intersection type case, and at this time I haven't thought deeply about how to handle this nor have really any idea how to achieve this. (but someone else may be able to sort that out?) That said, to me it also feels like the `null` type/value is "special", and that PHP has a history of "nullability" being more than "just a union where one of the types is `null`", making "nullable intersection types" desirable (even without waiting for [hypothetical] full composite types). But I fear that most of the previous points still apply... > Another argument is that ?A&B might collide with a future syntax. But I > fail to see how. For sure we create examples of such collisions, but they > all look constructed to me. > > Shouldn't we allow ?A&B ? Intersection types look unfinished to me without > compat with nullables. > > Cheers, > Nicolas > -- Guilliam Xavier