Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:115598 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 42214 invoked from network); 28 Jul 2021 02:35:08 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 28 Jul 2021 02:35:08 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 8ADE8180505 for ; Tue, 27 Jul 2021 20:02:13 -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-ASN: AS15169 209.85.128.0/17 X-Spam-Virus: No X-Envelope-From: Received: from mail-lf1-f45.google.com (mail-lf1-f45.google.com [209.85.167.45]) (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, 27 Jul 2021 20:02:12 -0700 (PDT) Received: by mail-lf1-f45.google.com with SMTP id z2so1223161lft.1 for ; Tue, 27 Jul 2021 20:02:12 -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=2zIF/0QiYVM9B8d2alE9JXF1GtdrK0TmoFHDuv4AZHI=; b=KZHj5MQ1y34andgyqNaPHQyIE0L1HR1/LNnyWiqWXtBi6xEluhfOUX4wwZgQzQFGOv ohcWqDe3Vb6mPP4TZVmnNmpawd8W4JC1eI0P/6TazHR6ZvrTVQxZ3FGtumqDuIPi6maH H+rBgPZql/g/mZ+IWUmib8atLvsPQWag/DtpJbXerZp6CklH+JSDrI5uPlAlYhqybN1X wJfF4Uf8/UcJVdw/nxHkreAl/xiaK+b1MG0//hQkH53ZD+CmyziLZiSe/OAvwjqXlUOb Hlv0q1R4TCLfZNJKhiYrFIkESA3ktCPpNRPMsvI58d97XW7vBcXSVm3cPc8J63owyCX5 A6dA== 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=2zIF/0QiYVM9B8d2alE9JXF1GtdrK0TmoFHDuv4AZHI=; b=qU/ba9j1IR8AXQ+I0g2JGewmyeacSmt3VhpMO8Vf+BrhunJSzZbN+IeHik6OAGik2S jQtylCUXOk/aumIixrQuXO7DGx289IDi0hESdNBS5QEiIW8MlU0D2qAZWaC0bVwJNozu dGSj7hqU0ajvcpgtfaeqI2ZNXMU1XUbOBF13UOLcK5IbYAXP1OMrOiOYKVaQwwAqtG0U zt7K2RaLPeQLt6rhoyBkNVOZY8j0HoBx/lkSmSJ0AsCd0aJxo5NGtwP7Hw+O2UGZKwNr Eb0U4spiSMnN8BM0M1qkokzx1Uaw8N92Jsv4EVj1F90ChcS56TvGzvWpVEOfLkWrqq5W 3pmg== X-Gm-Message-State: AOAM530qd2FWsZD1fWadikCsHI97I0P9LGoClEWEuPQKxq9SP4Pf6teT pHXKzyQBZffqH+v5ozia6Enb5e3TlROejWc4AR0= X-Google-Smtp-Source: ABdhPJx4W8q7qvjn/PcXIpQpqRfY52duqire8cpunN5iztQjT9hk/12O2jABDXwdhlr+E3e9ZEo4BjPfFJrn632JKB4= X-Received: by 2002:ac2:4d86:: with SMTP id g6mr18572794lfe.549.1627441330205; Tue, 27 Jul 2021 20:02:10 -0700 (PDT) MIME-Version: 1.0 References: <002e01d78326$27ed0680$77c71380$@webkr.de> In-Reply-To: Date: Tue, 27 Jul 2021 20:02:11 -0700 Message-ID: To: Pierre Joye Cc: Rowan Tommins , PHP internals Content-Type: multipart/alternative; boundary="00000000000061367c05c82636bb" Subject: Re: [PHP-DEV] [RFC] Nullable intersection types From: jordan.ledoux@gmail.com (Jordan LeDoux) --00000000000061367c05c82636bb Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Intersection types are very useful if you use composition over inheritance. That is, in PHP, they are most useful when you are using multiple interfaces and/or traits to represent different aspects of an object which might be present. For example, using an actual library I maintain, I have a concept of different number type objects. NumberInterface - Anything that represents a cardinal number of any kind will share this. SimpleNumberInterface - Anything that represents a non-complex number will share this. DecimalInterface - Anything that is represented as a float/decimal will share this. FractionInterface - Anything that is represented with a numerator and denominator will share this. ComplexNumberInterface - Anything that has a non-zero real part and a non-zero imaginary part will share this. To correctly represent the return types for, say, the add() method on Decimal, what I would *actually* return is something like NumberInterface&SimpleNumberInterface&DecimalInterface. The add() method on Fraction would instead return NumberInterface&SimpleNumberInterface&FractionInterface. Now, internally, the add() method has a check for whether there is an xor relationship between real and imaginary parts of the two numbers. If there is, then a complex number object is returned instead. This means that to fully describe the return type of this function, the type would look like this: function add(NumberInterface $num): NumberInterface&( (SimpleNumberInterface&DecimalInterface) | (SimpleNumberInterface&FractionInterface) | ComplexNumberInterface) It can return any combination of these depending on the combination of types provided as arguments and being called. Now, if I got to just dictate how this was implemented from my own userland perspective, I'd provide typedefs and limit combination types to those. So, my ideal implementation would like like: typedef DecimalType =3D NumberInterface&SimpleNumberInterface&DecimalInterface; typedef FractionType =3D NumberInterface&SimpleNumberInterface&FractionInterface; typedef ComplexType =3D NumberInterface&ComplexNumberInterface; function add(DecimalType|FractionType|ComplexType $num): DecimalType|FractionType|ComplexType But as I've mentioned earlier, none of this is really affected by nullability. To me, that adds very little (though not nothing). Since it accepts class types instead of classes themselves, I'd make an OptionalInterface that provides the tools to return a null instance that has useful information for the user of my library about why the object is "null". Full combination types between unions and intersections is something that I would use heavily, but to me that means it should be implemented carefully and thoughtfully. As they are currently, I would use intersection types less often, but they will still be useful in typed arguments. I can provide actual github references to the code of mine that would change if that would be helpful, but I wanted to provide a broad example of how intersection types in general might be useful and how they might be used. Jordan On Tue, Jul 27, 2021 at 6:14 PM Pierre Joye wrote: > Good morning, > > On Wed, Jul 28, 2021 at 5:52 AM Rowan Tommins > wrote: > > > > On 27 July 2021 21:29:47 BST, "Andr=C3=A9 H=C3=A4nsel" = wrote: > > >> In fact, when 7.1 was released, none of the signatures changed in my > > >code, they were just > > >> updated to a different syntax. > > > > > >That by the way is only because of a specific compatibility behavior > > >which is so confusing > > >that I erroneously reported it as a bug: > > >https://bugs.php.net/bug.php?id=3D80948 > > > > > > I can see how it would be confusing if you're coming to PHP fresh in th= e > last few years, but from version 5.1 though to version 7.0, that was the > way you marked nullable parameter types. > > > > It's a "compatibility behavior" only in the sense that it wasn't > immediately removed when the more flexible "?type" syntax was added in 7.= 1. > > I get the feeling the nullable type syntax was not very well noticed > by users when it came out. However it is not what is confusing I > think. intersection, types on the other hand, are. I have yet to find > usages so critical that we had to rush that in in an incomplete > manner. I personally prefer how it is done in typescript, but same > thought, I have yet to see good code design using them. ;) > > Best, > -- > Pierre > > @pierrejoye | http://www.libgd.org > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > > --00000000000061367c05c82636bb--