Newsgroups: php.internals
Path: news.php.net
Xref: news.php.net php.internals:115491
Return-Path: <guilliam.xavier@gmail.com>
Delivered-To: mailing list internals@lists.php.net
Received: (qmail 15280 invoked from network); 19 Jul 2021 13:44:25 -0000
Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5)
  by pb1.pair.com with SMTP; 19 Jul 2021 13:44:25 -0000
Received: from php-smtp4.php.net (localhost [127.0.0.1])
	by php-smtp4.php.net (Postfix) with ESMTP id 925241804E2
	for <internals@lists.php.net>; Mon, 19 Jul 2021 07:09:25 -0700 (PDT)
X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net
X-Spam-Level: 
X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,
	DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,HTML_MESSAGE,
	RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS
	autolearn=no autolearn_force=no version=3.4.2
X-Spam-Virus: No
X-Envelope-From: <guilliam.xavier@gmail.com>
Received: from mail-lj1-f178.google.com (mail-lj1-f178.google.com [209.85.208.178])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256)
	(No client certificate requested)
	by php-smtp4.php.net (Postfix) with ESMTPS
	for <internals@lists.php.net>; Mon, 19 Jul 2021 07:09:25 -0700 (PDT)
Received: by mail-lj1-f178.google.com with SMTP id q4so26458680ljp.13
        for <internals@lists.php.net>; Mon, 19 Jul 2021 07:09:25 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20161025;
        h=mime-version:references:in-reply-to:from:date:message-id:subject:to
         :cc;
        bh=f4iFbwLIVaTUoNExPZ1EMLdo0Fki4wficpkUxX+l37Y=;
        b=s2E4BONC1MqbxH2LF+zG9Pzt69/Wj+mHDiRsTCLlGZ8nKl3tr+K3I/usshKQmXmiYa
         PF9ejNUl5ru7GstQR9hEmz19Rbnt8xW4VHq1CWJHgSy1XlCrlwv7Tmg5SAyn4aPsXO7D
         0udcOMYgXgRX/qP5gCBM2zDaYlNhpEu0AlZGEvd0PJ3dvBs4EDNZkUcjdVEzdzWPx9O6
         GWygfrLEIp1LWJFr4fTBc4mkLzbKIJmdy49szd6kS0kpvDJKnxXr7eDJ/egj/C7Ob/hO
         b1utVMg0f8OtGN6X9e7ea28XPrRS3W0KA5oKWl+W+2pHdWqkO0YR/fd0N13HyZINX5Kf
         6x6A==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20161025;
        h=x-gm-message-state:mime-version:references:in-reply-to:from:date
         :message-id:subject:to:cc;
        bh=f4iFbwLIVaTUoNExPZ1EMLdo0Fki4wficpkUxX+l37Y=;
        b=hSeXud1fEN+G9IuZHW5Cd87lFKvNoahHatwVqbjaA3CL1laRyWPFIBBD10VXcQLq72
         qX32qAsN9CUp2L6EfbIKNQI522xsJ869ClnZWpwn96nwPmVzBqKmJpodsTp7ukPNcnPj
         qOlzOZGXJaujdDrkL7ULPNqcqg/Gj1ukaUerkhAA6w5MlapbU3nFr+XA+kbVIjFmYKhk
         vzb9u7afyQDyqTfVmB8MT0b4pYysH2rz2T6ZG8c16mBsD5zIf4uQGusKuVwBZC/M/TTb
         lkMwCXIK6lD9QJIfUJbEfY5AR4lcKxsAgdC5Wxlv+eGu5Qf9jFCNuHJuD2coGoJaNMLF
         K1Nw==
X-Gm-Message-State: AOAM531swK6FyIvk6I2I0Ar7PNMcR6Gm+my6ljY1cr3lUCcigBhoYP7Z
	vbNMa4+YhUF5WghAzRPMximvDSwHWYgZarmqNQ==
X-Google-Smtp-Source: ABdhPJyVqd5rPs1A1vaERkLrGydzp0ZfyHmhYopMpLAkWEq7owyNXWYkvcHrOnd4ordzi2b7vsWSHCP3RVjrUvc4dDY=
X-Received: by 2002:a2e:5c03:: with SMTP id q3mr22152929ljb.233.1626703760218;
 Mon, 19 Jul 2021 07:09:20 -0700 (PDT)
MIME-Version: 1.0
References: <CAOWwgpm+PPhW6A5=Oi1tpdkQh9COGw5dQLE+Ek1p0BZ6T-xQsA@mail.gmail.com>
In-Reply-To: <CAOWwgpm+PPhW6A5=Oi1tpdkQh9COGw5dQLE+Ek1p0BZ6T-xQsA@mail.gmail.com>
Date: Mon, 19 Jul 2021 16:09:11 +0200
Message-ID: <CAC5V6ggeLQYygZq13-Ux0VoSDiMUhAPR3Wr9AoT_oDoqu9yxgw@mail.gmail.com>
To: Nicolas Grekas <nicolas.grekas@gmail.com>
Cc: PHP Internals List <internals@lists.php.net>
Content-Type: multipart/alternative; boundary="000000000000c85d0105c77a7b96"
Subject: Re: [PHP-DEV] intersection types and null for defaults, properties
 and return types
From: guilliam.xavier@gmail.com (Guilliam Xavier)

--000000000000c85d0105c77a7b96
Content-Type: text/plain; charset="UTF-8"

On Mon, Jul 19, 2021 at 10:41 AM Nicolas Grekas <nicolas.grekas@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

--000000000000c85d0105c77a7b96--