Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127174 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id E51451AEAF8 for ; Wed, 23 Apr 2025 09:47:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1745401497; bh=WE2dwlowCaimvNkvLFOq46hD0nyAjV8e/BnV8q8ePEQ=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=MlpFpFX98OyEchQVF68FUXQh5S+cZ4wH6txPeIyrqymjmIdqKx6BlWC55uA355NI0 4RHFuiAyS7AhP1Kxi8/PLasQO/APICdYzPU9MIzDTCN8ZxBtIpjJbWH2noV27NQrc+ J6JHGF1e8cMvWe+7ghq445Xz0k2q+vxSLilfounFhWiGOeRF6010CAmdJHa4qmPCX8 R6iLC4OrJ+JGN7fIyoy3ZdLXR8eSwF7aenmU0fUDwZwwNqZ7uRrYR57hx+XjAZjJml wZB3r7nvT96tC/XDLt2zyg7CIineOp97PZSlioPWoeuStEknn95lut+0h012AhlvSt zO+x9uCc4ocFw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id BEE14180084 for ; Wed, 23 Apr 2025 09:44:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-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,DMARC_PASS,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from mail-yw1-f169.google.com (mail-yw1-f169.google.com [209.85.128.169]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Wed, 23 Apr 2025 09:43:29 +0000 (UTC) Received: by mail-yw1-f169.google.com with SMTP id 00721157ae682-6feab7c5f96so53669817b3.3 for ; Wed, 23 Apr 2025 02:45:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dqxtech.net; s=google; t=1745401547; x=1746006347; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=OjNnIe3+o7iqGskx7zlc0SrA90ORrt9ZtjkwKyElG4E=; b=cJnYz0Y6WvDfN2yUT8ueJLQSnQzghyCIyj3vfQ1A4TCTv3H6AshsSlbYww8Qw9NPKl u1ITp3Q+15hxwnLTaWFpJOdqRB0j3zXMcOSal9QTcM5jK6sImu+Jp48I0qsNgHN3B1iI 1IjZ5bU8PNe6HX1LHqZ24E/HuLnvVfv89Cim10s1w7LmTEAFbZuTdFO9x19yzoebyUNk lZIFKHo7JyEVoqXEvBZtoTnMyJuDUwXNSL/HJx6N8N5dZMbhAbKVu54LpbSuzCRmw0xg INx6BhXstvXzW5AezK/FiBP2O4X3uolPomvQHf6Y8fyQ3eR/M2br2F20gqdMiN+Y3jYg 6lZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745401547; x=1746006347; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=OjNnIe3+o7iqGskx7zlc0SrA90ORrt9ZtjkwKyElG4E=; b=h88LvNBaixO/eJar4OyN465UthXxIPS29+SlYtJ3BPU99xEN5xqAQaKspPrvj9UQoA fKgO6fvH/4r/4YJCWLg+CbW4z/BywzO5fa8VIx8Yo9rmKKLOKCDunvCTi00a8wqK1hGl JQMW1ovIsFSxIIN0En+XKafMThnfdjEy98wST4PfDKuQdhqSeXRBgUNLurQrTjPxff0a zX2wvCZkrHpAuotipcCunpwIf7eXb/WjNO1OpNfMDZoVtYWeateU8I/QKaK+L7dMHdXU gewF6yzkCGeo8wtOWimJGqL0sKzUPZBP1iDnKO0yybp3QAzdzM/oOOmWSr1UxRL27I24 M5Mw== X-Gm-Message-State: AOJu0Yy/8638WE+woWgI33lzBl6UiMtUaGqPez3cUGKYXE0XwnVJnBd7 urKRt/PHCElEacVSMmwiC1RSU/HuhUXqYNF0BJbkY9BiPifWP8bsSXCJlKjOSsC2yW9DVLEgwVC M74Swj4W79kMUNpQ9XpgpO6Fw6b131HfqV5inykre5J+Dyx2vr+GX7b9A X-Gm-Gg: ASbGncs4rYy0pKyeEAS+ut0CAEizP25KSxpJD/XFYzv/v9lBLZJ8hNHaEuiG1y9UzMj /tvWqkxEtWaNAy2aaYH+h2yBAqukK7vjGl5G64t/SkyLBA6kCvchU1VyUrad1Z32E/f+NN/74lY ANq45gFqda9z3lyHEH5Yvu X-Google-Smtp-Source: AGHT+IGNvzKEfUjPht5MoIJCvM/j29zFk+lA8/CcngAEKqnp9HVORamR6/Af/d81Q0eszT8TAwGVsOt+vWORS3xviuQ= X-Received: by 2002:a05:690c:25c8:b0:702:d54:45be with SMTP id 00721157ae682-706cce101cfmr250475497b3.35.1745401547527; Wed, 23 Apr 2025 02:45:47 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Wed, 23 Apr 2025 11:45:36 +0200 X-Gm-Features: ATxdqUExEji8m1Gwvo_3VbC7x920Atg9d8HT_czJQz9KoH3f1tR2BOTnWsreKsQ Message-ID: Subject: Re: [PHP-DEV][Pre-RFC] Associated Types To: "Gina P. Banyard" Cc: PHP internals Content-Type: text/plain; charset="UTF-8" From: andreas@dqxtech.net (Andreas Hennings) On Tue, 22 Apr 2025 at 19:39, Gina P. Banyard wrote: > > Hello internals, > > The discussion about allowing never types as parameter types made me think about what problem it is truly trying to solve, > which is using the same type as parameters and return values between multiple methods of a common interface. > > This is normally solved with generics, but as shown generics are hard TM [1] and a lot of the complexity resides in allowing the generic type to be set at *use* site of the class with generic parameters. > However, this does not apply to template/generic types on interfaces, as the bound type is determined by the implementing class at compile time. > > As such, a few weeks ago, I created a PoC [2] where one can declare a template/associated type T on interfaces that require an implementing class uses the same type when specifying T. > > The syntax in the PoC is currently: > ``` > interface I { > type T : int|string; > public function foo(T $param): T; > } > class CS implements I { > public function foo(string $param): string { > return $param . '!'; > } > } > ``` > > I.e. the associated type is indicated by a "type" keyword, optionally followed by a colon `:` and a type constraint. > The type corresponding to the associated type is currently "guessed" by the first usage in a concrete class. > > Having talked with Arnaud off-list, it seems that using the "usual" generic syntax of (assuming our parser can cope with it): > ``` > interface I { > public function foo(T $param): T; > } > class CS implements I { > public function foo(string $param): string { > return $param . '!'; > } > } > ``` > is possible and would not conflict with any future proposal for generics. > > Importantly, this feature would NOT support doing the followings: > - `$o instanceof I` > - Using `I` in type declarations > > Meaning you do not get static type information, similarly to the `never` as parameter type, > but one is guaranteed that there is no funky type variance and incompatibilities between different methods (or parameter and return types of the same method) in a concrete implementation of an interface. > > Effectively, static analysis tools must either assume T is `mixed`, or hook it into their generic types feature. > Which is what the current status is for various interfaces (e.g. ArrayAccess). > > I am intending on getting this feature ready for 8.5, and the reason I bring it up to the list now, without a proper RFC, is to explain my reasoning for why I am voting against the never parameter type RFC. [3] > > For any questions, feel free to reply, but please do remember that this is still a bit in flux. > > > Best regards, > > Gina P. Banyard > > [1] https://thephp.foundation/blog/2024/08/19/state-of-generics-and-collections/ > [2] https://github.com/php/php-src/pull/18260 > [3] https://wiki.php.net/rfc/never-parameters-v2 Hello Gina, what I miss in this proposal is whether and how we can use the "generic" interface as a type hint. > Importantly, this feature would NOT support doing the followings: > - `$o instanceof I` > - Using `I` in type declarations So, can we still do "instanceof I" or use "I" in type declarations? And if we do, how can we then determine the associated type of an object at runtime? To be clear, the never type does not magically solve this problem either, it just fills a niche. But, there are patterns that involve the never type and union type which can solve it.. interface AcceptsA { public function foo(A $arg): mixed; } interface ReturnsR { public function foo(never $arg): R; } class C implements AcceptsA, ReturrnsR { public function foo(A $arg): R; } function foo(ReturnsR $obj, A $arg): R { if ($obj instanceof AcceptsA) { return $obj->foo($arg); } [...] } The never type also fits a natural niche in generics: interface I { public function foo(never $arg): void; } interface IT extends I { public function foo(T $arg): void; } We could also say that implicitly "IT extends IT", if T is marked as contravariant somehow. interface I { public function foo(T1, T2); } function foo(I $obj) { if ($obj instanceof I && $obj instanceof I) {...} } Not sure where this is going in the end, but I have the feeling that use cases for a "never" parameter type will appear. An interface-only generic syntax can be a step towards generics, but I don't necessarily see it as an alternative to a "never" parameter type. -- Andreas