Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:115752 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 43133 invoked from network); 16 Aug 2021 07:19:43 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 16 Aug 2021 07:19:43 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id F03181804C8 for ; Mon, 16 Aug 2021 00:51:38 -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-lj1-f170.google.com (mail-lj1-f170.google.com [209.85.208.170]) (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 ; Mon, 16 Aug 2021 00:51:38 -0700 (PDT) Received: by mail-lj1-f170.google.com with SMTP id y6so9050565lje.2 for ; Mon, 16 Aug 2021 00:51:38 -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=AaqtDfDIHxOBYAptwi/I3LPkZPjrG58DybJAqxv5N/0=; b=fOBd9Eqf0tNbBILzJS6+Gj6q4tuSZJzDZs6t5v0OmnTXUn8aEyAHybWGBB4X+7ouls XoL++N4d6AVeFLuaNves2uQ9fGaqhVOaSM/kOnpsYTD0GgGMYS5IUKYZgBJgzYgx7TQT QJdpZsUa+VdUVgSGtK61DI4aDH8V6czjURZIsMcKuD3UwSakEmAcribkP1F4ZWBrY3l6 MSzcMv776CKVUquplAWdcok2zbjD/wMWqYL925HgWeQ5NIWeYYMFluoHeqMBcKQdzQhi KB2bk46HIE9ZAgGA6+b0WilCGKfF99DMt4HAOtYBa3+zGSVjvWNjdQhDcuz7VKjPLax1 Agrg== 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=AaqtDfDIHxOBYAptwi/I3LPkZPjrG58DybJAqxv5N/0=; b=Plvx0G8jEMD3MSuGWdtYH7S8xria5jGDcEH7Ds2682xJCD3YO/v+UfUKwQsCVDNG9V 9jVA71hpsG41fGLayoHnzBJmrNqF/ioVDmEvaBqYhw54JMITMWDDDUoEtgVgTA51BY7i 5ADVYDawKW+0/Cyq1guIuXfWtGU0EZMCMq8Iz7HsXkRuPFKoBAx1h5zCt94t2btAB01X Vg/ukAotuizeeaANxM2qzwLKap0md4lPrnp/8i7AdypUw+YsuOHmAS+ts5p324Ypf7SV bZ9Dp7LsG+h+TUsqijgGZg5LoYaHCypS2LUM3Hb/FBOQ6h9ofExkMjYGidsgpw5uE9cQ Hjfg== X-Gm-Message-State: AOAM531yB/05fOoly4z8ZoQB3zCVJux0/d9nU0+JPB5i48GEaDDuIOik T7IuRnFEIPQWxDbvH/qwsDzFrXzizKINL8h99z0= X-Google-Smtp-Source: ABdhPJymzuFjXG1a5pYR77N85ApAYhM2wbD+oAIuLwZiL2ujzk31FmWPvyOmgpeCJ+gxLIz4syOeaGveQ7ZEc2zCI9E= X-Received: by 2002:a2e:bd16:: with SMTP id n22mr11913974ljq.29.1629100293922; Mon, 16 Aug 2021 00:51:33 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: Date: Mon, 16 Aug 2021 09:51:17 +0200 Message-ID: To: Jordan LeDoux Cc: PHP internals Content-Type: multipart/alternative; boundary="00000000000052a1d305c9a87899" Subject: Re: [PHP-DEV] [RFC] Never For Argument Types From: nikita.ppv@gmail.com (Nikita Popov) --00000000000052a1d305c9a87899 Content-Type: text/plain; charset="UTF-8" On Sat, Aug 14, 2021 at 3:44 PM Jordan LeDoux wrote: > > > On Sat, Aug 14, 2021 at 6:25 AM Nikita Popov wrote: > >> >> function addMultiple(CollectionInterface $collection, mixed ...$inputs): >> void { >> foreach ($inputs as $input) $collection->add($input); >> } >> >> A static analyzer should flag this CollectionInterface::add() call as >> invalid, because mixed is passed to never. Effectively, this means that an >> interface using never argument types cannot actually be used in anything >> *but* inheritance -- so what is its purpose? >> >> > When used as a sort of... pseudo-generics replacement, you'd need to use > Docblocks to specify these, because **this feature is not generics** (which > you correctly pointed out). I probably should have made that MORE clear so > as to not confuse or trick anyone. > > If this RFC were passed, it could be sort of used like generics but it > would be a bit hacky to use it that way as your example illustrates. In the > absence of generics, this would probably be used as a stopgap in > combination with docblocks. That's the point I was trying to make. :) > > The main value I see from an inheritance perspective is using never to > disallow an omitted type. The inheriting class may specify *any* type, even > mixed, but it must do so explicitly. > I don't think this really addresses my concern, so let me repeat it: You cannot actually call a method using a never-type argument while typing against the interface. What's the point of the interface then? I don't think "you must use this in conjunction with a 3rd-party phpdoc generics implementation for it to make any sense at all" is a suitable way to resolve that. The only case where this is somewhat sensible is with interfaces controlling engine behavior, like the operator overloading interfaces Addable etc you clearly have in mind here. If you never actually type against them and only use them as a marker for the engine, then this works out fine. But this still leaves the interface useless from a typesystem perspective, it merely becomes an engine marker. We have a better way to specify markers for the engine: Magic methods. I think some people have a mistaken notion that engine-integrated interfaces are always better than magic methods. This is only the case if such interfaces are actually useful from a type system perspective. For example, Countable and Traversable are useful magic interfaces, because you can sensibly type against them. The recently introduced Stringable interface (for the magic method __toString) falls in the same category. Conversely, Serializable is actively harmful as a magic interface (apart from the other issues with it), because whether an class implements Serializable does not determine whether it is serializable -- all objects are a priori serializable, the Serializable interface just gives it custom serialization behavior. You'll note that the new __serialize/__unserialize methods are plain magic methods without an interface. With exception of a custom serializer implementation, user code should never be checking for Serializable. The operator overloading case is in between: The interface is not actively harmful, but they also aren't useful. Given the lack of generics, it's not really possible to write code against a "Multiplyable" interface that actually provides a useful guarantee. The interface does not distinguish whether "T * T" is valid, or only scalar multiplication "T * float" is supported. When working with operator overloads in PHP, I expect usage to type against a specific class implementing operator overloading, say Money, rather than typing against something like Addable&Multiplyable. The latter would accept both Money and Matrix, both of which have entirely different rules on the kinds of operands they accept, even if they are, in some sense, addable and multiplyable. Regards, Nikita --00000000000052a1d305c9a87899--