Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:115580 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 98972 invoked from network); 24 Jul 2021 21:05:25 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 24 Jul 2021 21:05:25 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 20E131804D0 for ; Sat, 24 Jul 2021 14:31:45 -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.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS11403 64.147.123.0/24 X-Spam-Virus: No X-Envelope-From: Received: from wout2-smtp.messagingengine.com (wout2-smtp.messagingengine.com [64.147.123.25]) (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 ; Sat, 24 Jul 2021 14:31:44 -0700 (PDT) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.west.internal (Postfix) with ESMTP id BABCD32008FC for ; Sat, 24 Jul 2021 17:31:42 -0400 (EDT) Received: from imap43 ([10.202.2.93]) by compute1.internal (MEProxy); Sat, 24 Jul 2021 17:31:42 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm3; bh=Ig230PxBYgyAOiVBJIyQZXoZ3X660ifGRrqRdq1WS fA=; b=HNV4agypGzLrd+j1dSh/j+rp6PjSCigUxXldIZiY8uVq97B8LKh9PTHxn AM3pkOYTKowe39ePeajT574DgXrt6caDoto4cZpsADJjVCOfKbDvZ8pI9qwt6RgX SbW1mruCwpIRMzgc1tKLpBeQPBFcbjuyiTgPIppM1hFbAdJaS/y0vV+GsyvvVq6B vjrueNSaikzGUXZ1WwEEXbebDQjlMIYslAyf6Q2I2kLAQQmTiJYcGch+H9VIincO BBcSuKASB3/yOTPxV01/YiPJxraasgzUWOa6Wlusdcff/eEV2byvwIIole4HOdk9 q1Sme0tjMrTOfUhcbCX/MnfObBrSQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvtddrgeduucetufdoteggodetrfdotffvucfrrh hofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgenuceurghi lhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujfgurh epofgfggfkjghffffhvffutgfgsehtqhertderreejnecuhfhrohhmpedfnfgrrhhrhicu ifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomheqne cuggftrfgrthhtvghrnhepffffffejffdugfegvedviedttedvgfejffefffejleefjeet veehgefhhfdvgfelnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilh hfrhhomheplhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtohhm X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id 18817AC0E90; Sat, 24 Jul 2021 17:31:42 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.5.0-alpha0-540-g21c5be8f1e-fm-20210722.001-g21c5be8f Mime-Version: 1.0 Message-ID: In-Reply-To: References: <353F9140-7E59-4CD4-95D3-9BA8F9CA6C29@newclarity.net> <43D8F75F-09B0-4AE4-A9EB-8775E231B367@gmail.com> <94F0E6DA-8C69-402D-B6B2-5EBDEB6638FB@newclarity.net> Date: Sat, 24 Jul 2021 16:31:21 -0500 To: "php internals" Content-Type: text/plain;charset=utf-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [PHP-DEV] [RFC] Nullable intersection types From: larry@garfieldtech.com ("Larry Garfield") On Sat, Jul 24, 2021, at 12:33 AM, Tobias Nyholm wrote: > >> @Larry makes an argument to keep them:=20 > >>=20 > >>> Requiring parenthesis now leaves the option open in the future to = make them optional when doing full mixed types. > >>=20 > >>=20 > >> I don=E2=80=99t understand why we should require something that is = not needed simply because it would give us an option to remove it later=E2= =80=A6 Could you elaborate why this is important? (Im probably missing s= omething) > >=20 > > The difference is if we make the decision to use the `?X&Y` syntax a= nd we later realize it was a mistake then we are stuck with it.=20 > >=20 > > OTOH if we use the (X&Y)|null syntax and later realize it is okay to= also allow `?X&Y` PHP could later be changed to allow it. > >=20 > > The later is the choice that manages future risk better. >=20 > I thought Larry was discussing `X & Y | null` vs `(X & Y) | null`.=20 > I=E2=80=99ve dropped `?X&Y` because Derick had technical arguments aga= inst it.=20 >=20 > The way I see it, there is no benefit in requiring the parentheses in=20= > `(X & Y) | null`. I suggest we use `X & Y | null`. Let me expand on my previous point (though those who have restated it ar= e essentially correct). 1) Full mixed intersection and union types is something that we want to = do in the future; it may or may not happen in 8.2, but it's something th= at should be considered on the informal roadmap. 2) Therefore, IF nullable intersection types are added now, they MUST be= added in a way that is future-compatible (syntactically) with full mixe= d types in the future, as nullable intersection types are by definition = (in PHP) a reduced-scope form of mixed types. To do otherwise would cre= ate a needless inconsistency in the language. 3) The parsing logic for intersection types is already bonkers, and has = to do some wonky shenanigans in order to work. 4) At this time, it is unclear if it will be *technically* possible to s= upport `Foo&Bar|Baz` as a syntax. Whether it is desireable or not is su= bjective, but whether it is possible at all is an unknown at this point.= Given the complexity already in place, it may not be possible, no matt= er how much anyone argues that it's "obvious" based on math. If the tec= hnical answer is no, then the desireability question is entirely irrelev= ant. 5) Point 4 means that we simply don't know if `X&Y|null` will be extensi= ble to X&Y|Z. It may be; it may also be impossible or infeasible. Poin= t 3 means I would be highly skeptical of that being the case, and thus w= e should assume it is not. 6) That means there are a couple of possible end-states, assuming X&Y|nu= ll is implemented now: A) X&Y|Z and (X&Y)|Z both work fine, whether Z is null or not. B) X&Y|Z works iff Z is null; if it's not, then you must do (X&Y)|Z. C) X&Y|null cannot remain supported once full mixed types are supported,= at least not without still-more special casing and shenanigans. That m= eans either breaking BC, never implementing full mixed types, or having = a wonky one-off in the engine forever. D) Some other mechanism such as the sometimes discussed type aliases pro= vides an alternate way to solve this problem. (Eg, you have to pre-defi= ne a complex type Foo =3D X&Y|Z, and then in a function signature you ca= n type either Foo or ?Foo.) As of right now, *we do not know which of those will happen*. I think m= ost would be fine with A as an outcome, but there is very significant ri= sk of C happening, and C is a bad outcome. Even if B could be done with= a minimum of engine wonkiness, it would still be a sub-ideal state from= a developer point of view. And D is still a very open question that ma= y complicate the whole situation further. Thus, IF nullable intersection types are supported now, we're basically = guessing on whether it will be possible to support mixed types in the fu= ture without parentheses. If we guess that it will be possible, and we're right, spiffy! If we guess that it will be possible, and we're wrong, we're in case C a= bove. This is the worst outcome. If we guess that it will not be possible, and we're right, spiffy! If we guess that it will not be possible, and we're wrong, then people u= sing nullable intersection types get a bonus new feature along the way. Of those, the only not-happily-ever-after alternative is guessing the pa= rens will be optional and being wrong. Everything else works out OK. T= hus, we should guess that it will not be possible, as that can only lead= to a positive outcome whether we're right or wrong. Based on the above logic, I will not be voting for this RFC if it does n= ot include parens, as it is too risky given the open unknowns around wha= t will be possible in the future. ------ Separate from the technical argument, the question of how necessary it i= s: The assertion that intersection types are useless without nullability is= facetious and wrong. Are they more useful with nullability? Yes, I do= n't think that's really debatable. But not-useful is incorrect. PHP 7 scalar types *were* useful. They *did* get used. Just not in as = many cases as they could have been. However, I still die a little insid= e every time I have a nullable argument/return. To me, nullable always = means a design flaw, even if a small one. (I still use it, but I hate t= hat I have to.) The overwhelming majority of my type declarations are n= ot nullable, and so would work perfectly fine with intersection types. I have no data on just how many libraries skipped 7.0 as a target versio= n, but to assert that "everyone" did so because of the lack of nullabili= ty is simply absurd. Here's a bunch of other perfectly good reasons why= a library would have skipped 7..0 as a target, many of which I know pro= jects did do: 1) PHP 7's unified variable syntax was a PITA to update to in some cases= , as it's hard to test for. By the time projects really worked all that= out, 7.1 was out anyway. 2) PHP 5.6 had an extra-long support lifespan, so there was less incenti= ve to do so than usual. 3) Even today aggressively tracking new versions is unusual, based on th= e Composer stats. 6 years ago it was even less common. What is super c= ommon is for projects to skip several required versions all at once when= doing larger overhauls. (That includes Symfony.) 4) Linux distributions come out less frequently than PHP versions, so th= ey often skip over "officially supported" PHP versions. So yeah, to pin the entirely of PHP 7.1 seeing a larger uptick than 7.0 = on nullability is an entirely nonsensical and unsupported claim. That m= ay well have been true for some projects, but there is zero evidence tha= t was the primary reason for most projects, or even a major reason at al= l. I'm not against adding nullable intersection types now, but the "8.1 wil= l be useless otherwise" rhetoric being used to argue for it is inappropr= iate and unjustified. --Larry Garfield