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

Reply via email to