Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:115536 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 56813 invoked from network); 20 Jul 2021 17:15:23 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 20 Jul 2021 17:15:23 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 049DB1804F4 for ; Tue, 20 Jul 2021 10:40:41 -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=-1.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,FREEMAIL_REPLY, 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: Received: from mail-lj1-f169.google.com (mail-lj1-f169.google.com [209.85.208.169]) (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 ; Tue, 20 Jul 2021 10:40:40 -0700 (PDT) Received: by mail-lj1-f169.google.com with SMTP id h4so30829238ljo.6 for ; Tue, 20 Jul 2021 10:40:40 -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=soc1vKldXY36JjbpVmLGgaX7z1ekIBGaPSFzgRG6TxI=; b=uE2kz8EDisq2Ivf+MaidZmCrUyUtt+2t/nXn32FtqUuQ30CMMqhM0MXymIdpBxVJNX iibFXMk7JCJkDWHDAFtvkYIsmm3NGEFKFxJE/T/SmKdbHDKxhXzZKP7nvVJzATCEAxur xaXf/obWhZK8ed3o6+yj0naGvvlJrs+2qlCH5wKy4wOVzrUaveAY1nWsr0hTXbB+5AQl 1SyWqIwg4tDMF6LwK5UMS6uf8z3ej+iQc6+GC6WhNzDzUO5JmX48RqYwisAsm+DI0K4B h2wdH/S8sLd9yIz6pbZ+YrfMoq6zxyxtpCbFFSeJcHm7KuEeiEFWx2+P6iDGKoxuFL9u aBcw== 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=soc1vKldXY36JjbpVmLGgaX7z1ekIBGaPSFzgRG6TxI=; b=rDki+xsgGeYuP2nMGSSSnlxmC2sfmcwmdAnJZN4oC0dZ5vGSyBs/98y+FSTOQZNQjd Tn8O6+SleObv0eDle3Pas6dYA65MC9mw+7jwLg4q5+GZdNRPJ6yFx0ePfFbAO5GFxsYd biinNiWTHvU5HeT8EDu9aIe29swhgVsuO8rUGydbDIAWPaFWsatpBGUW+GTNjdz8Joto cj1xzedmuEjqAFHnOQu7tMpO+EOcUP/T0M+fHoGhb/RcYfJqpPn2uVuu2G9yLkUnq4lU 00s4jVosHyti3cYpaRC9aXZJcqpWJWMNdxjqqBEjA1lJgmTTyRiM8fnFV//AG70/CfBI FgrA== X-Gm-Message-State: AOAM530+nFQAPjqg/bgg9l44eou9HJU2fk+dutFzfImSnJRz7h/lg0/h dYY53zBiJBMsMt1L0YD27o+ThYNl/UxP95j2W60= X-Google-Smtp-Source: ABdhPJzwlUC/799hl8H1TaUxftwN4tjcUxg2qSx8qkYXjl2xbrx7qedxnHqB8nbHHgv+bSMzEDldj6py0JgK+EhATLY= X-Received: by 2002:a2e:900c:: with SMTP id h12mr27118429ljg.240.1626802838748; Tue, 20 Jul 2021 10:40:38 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: Date: Tue, 20 Jul 2021 10:40:26 -0700 Message-ID: To: "G. P. B." Cc: Guilliam Xavier , Dan Ackroyd , Nicolas Grekas , PHP Internals List Content-Type: multipart/alternative; boundary="00000000000052c05205c7918d21" Subject: Re: [PHP-DEV] intersection types and null for defaults, properties and return types From: jordan.ledoux@gmail.com (Jordan LeDoux) --00000000000052c05205c7918d21 Content-Type: text/plain; charset="UTF-8" On Mon, Jul 19, 2021 at 11:16 AM G. P. B. wrote: > On Mon, 19 Jul 2021 at 18:26, Guilliam Xavier > wrote: > > > On Mon, Jul 19, 2021 at 4:26 PM Nicolas Grekas > > > wrote: > > > > > > > > https://github.com/php/php-src/pull/7259 > > > > > > > Great! Thanks! Interesting how it works out-of-the-box with just this > > addition in Zend/zend_language_parser.y: > > > > ```diff > > type_expr: > > type { $$ = $1; } > > | '?' type { $$ = $2; $$->attr |= ZEND_TYPE_NULLABLE; } > > | union_type { $$ = $1; } > > | intersection_type { $$ = $1; } > > + | '?' intersection_type { $$ = $2; $$->attr |= ZEND_TYPE_NULLABLE; } > > ; > > ``` > > > > On Mon, Jul 19, 2021 at 5:09 PM Dan Ackroyd > > wrote: > > > > > nicolas-grekas wrote on the PR: > > > > ?X&Y cannot be confused with > > > > > > It confused me. A compiler might understand it, but as a human I have > > > trouble understanding it. > > > > > > Trowski wrote: > > > > The syntax should be either ?(X&Y) or (X&Y)|null > > > > > > Non-ambiguous syntax is much better than ambiguous syntax. > > > > > > > Maybe it's just a matter of habit? > > For instance I got used to seeing things like `!$x = f()` (e.g. `if (!$x > = > > f()) { throw /*...*/; } /* use $x */`) because some CS consider explicit > > parentheses in `!($x = f())` redundant (as PHP has a special case that > > "overrides" the normal precedence `(!$x) = f()` which would be an error). > > If you first consider `X&Y` as a type "unit", then it makes sense to make > > it "nullable" by prefixing it with `?`, I think? > > > > > > > > > > But this discussion is moot for 8.1. > > > > > > This limitation might make intersection types not be considered usable > > > by some projects, but the feature freeze is today. > > > > > > > Which can also be reversed: "The feature freeze is today, but this > > limitation might make intersection types not be considered usable by some > > projects"? (playing devil's advocate, I don't master the process) > > > > Regards, > > > > -- > > Guilliam Xavier > > > > Since when is usability for a specific project a consideration an RFC needs > to have? > If Symfony can't use it in its current state tough luck, > I'm sure plenty of other projects can, especially now that using 'new > Class' is possible as a default object value. > > I frankly don't care about being able to have some sort of partial union > possible with the usage of intersection types, > because it seems the machinery in the engine which makes null work, should > also allow any standard PHP types as those are part of a bitflag and > handling variance with them seems to work just fine... > > But for the love of god, this proposed syntax is horrendous, saying ?X&Y is > unambiguous is disingenuous. > It can either mean (?X)&Y = (X|null)&Y or ?(X&Y) = (X&Y)|null, the former > one being bogus as null&Y is an impossible type, something which should > error out to point out a potential bug in the same way we do for redundant > types that we know at compile time. > And if we allow this syntax then we really should be allowing ?A|B which is > dumb. > (and no ?X&Y is NOT something I consider forward compatible when it is just > going to become one more edge case we need to maintain because people have > no patience). > > If ?(X&Y) is allowed then ?(A|B) should also be allowed, and that needs an > RFC for sure due to the controversy it had in the union type RFC. > > The only remaining sensible choice is (X&Y)|null / null|(X&Y), but as I > said above if the machinery for null is there it must mean the machinery > for int/string/array/float/bool is also there, and frankly being able to do > something like (Traversable&Countable)|array is also extremely valuable, > maybe even more than nullability, but in any case this is going to be > confusing for end-users why only null (or standard PHP types) can be > combined in a union with intersection types. > > That's one reason why it's only pure intersection types, if I had more time > (or for crying out loud somebody would have paid me) to work on this I > would have loved to get full composite types working. > > And I find it frankly insulting that in the four month this RFC has been > published for discussion, with multiple push backs for voting due to bugs > and me wanting that people know what implementation is - for the most part > - going to land in php-src, this specific point has not been raised. > It just feels like you are pissing on 6+ months of *unpaid* work I did > because it doesn't suit your needs, and you just realised that and so > decided to throw a wrench into a carefully crafted RFC to "fix" it by using > a Twitter mob to put pressure on us/me. > > Maybe this topic didn't come up because for nearly everyone else "Pure > Intersection Types" means what it says on the can, moreso that in the RFC > the following line: > > This means it would *not* be possible to mix intersection and union types > together such as A&B|C, this is left as a future scope > makes it clear, and most voters also understood that '?' is not a type > "flag" but is syntactic sugar for 'null|'. > > There are plenty of issues with the implementation, from the whack parser > hack, the non support for static/parent/self, to the complexity of the > variance code, but I made all of those clear because they made *me* > uncomfortable with the implementation. > So if you are going to force this crappy syntax, then I'd rather axe this > feature completely (and nobody can use/play with it) then have something I > do not accept, nor are forced to accept because of a vote, land in core > making PHP even more of an inconsistent joke. > > Best regards, > > George P. Banyard > Hey George, > But for the love of god, this proposed syntax is horrendous, saying ?X&Y is unambiguous is disingenuous. > It can either mean (?X)&Y = (X|null)&Y or ?(X&Y) = (X&Y)|null, the former one being bogus as null&Y is an impossible type, something which should error out to point out a potential bug in the same way we do for redundant types that we know at compile time. It is ambiguous from a syntax perspective, but wouldn't it be rather clear from an intent perspective? As you note, null&Y is sort of semantically nonsense, as if someone did is_array() && is_bool(). I think this is what people have been meaning when they say it's unambiguous. Personally, I think intersection types are very useful even without nullability. Since intersection types only make sense with objects in the first place, the objects themselves should be able to provide better information about correctness than a simple null can, and such an effect could be achieved with a fairly trivial interface that maintains a single flag. I'm not entirely convinced that nullability on its own provides something that significantly improves the accepted RFC, except to support design patterns that have been used in the absence of this feature. Any situation in which I might want to use ?X&Y that I can think of would be better designed code if I instead guaranteed a state-aware object that I can interrogate. For example, in my own projects if I had the need for such a thing, I would instead use: X&Y&Optional. This would enable me to provide arbitrarily detailed information about the conditions of the optional nature of the data and an implementation of it that was aware of the nature of my program. That can't be easily achieved with nulls. I don't deny that ?X&Y would be used if it were available, but I wonder if this actually encourages code which is unnecessarily ambiguous itself. What it truly enables from my perspective is the ability to delay checking for violations of an expectation in a program until later in the code, and in this case I wonder if allowing that delay would simply enable implementations that are fundamentally worse. Any code which accepts ?X&Y would know less about the construction and configuration of the object than the code that actually constructed and configured it, and any code that returns a similar type would be reducing information about the state. In short, I don't see how this actually improves the language unless it addresses the full issue of mixing union and intersection types, which was definitely beyond the scope of the RFC. Jordan --00000000000052c05205c7918d21--