Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126986 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 E7B991A00BC for ; Mon, 31 Mar 2025 21:25:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1743456188; bh=9hvb/SS6NPcMRS6F6KccQMlyFPnlABC5qnB4T/B7TAM=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=AvVzr6Zuc7t0zcP+uj91kFPYbTyicVv7gIvXY/Nuen1q6oSW4i7nFtF1vZM/PmSki 16LK3l1pqfJnrBX6WtMKBf9xHBd5VEr9KC9JloCfaQTfsVBDVsk26O2sTEhToAP/L7 Pg/FyvdJKpXA9OzSaGj56XZta2aoq+N67xfyG1TeGDgPm/8bGTswMY8SCIiQAr+JLw W+QmtGxUl4MjZBN+3Z8PIZtLqzykLLia7oKdeqM3YGSrLabnAczRsjTzEq4SXiZzJS B1T+VwiYGcpqgksauXnLCLoB4WgxZr7tFpRFp+ZVhWaZszV5Vt57bopHvs06Nm4WtP 0Xe1xmCk11EKg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 937D4180082 for ; Mon, 31 Mar 2025 21:23:07 +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,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-pl1-f179.google.com (mail-pl1-f179.google.com [209.85.214.179]) (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 ; Mon, 31 Mar 2025 21:23:07 +0000 (UTC) Received: by mail-pl1-f179.google.com with SMTP id d9443c01a7336-223fb0f619dso92403265ad.1 for ; Mon, 31 Mar 2025 14:25:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1743456333; x=1744061133; 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=uVHNj+JtObElMyywTCHbfL1RCXVZFP608PFaksTvNto=; b=fTjzbyInEJhP1aLiKNkjmEm/vIu/57+0Vg9BO/PMecG5WAXAH10gv36OAuH0iI/JaT vu2fUPuB67cDEJDFzVIiz7DzIJI4LeO4gGJX44xSp3E6EachSOUJDTm96dRUFHbde490 p0UavwRAGJu2RmFbIRc3WGzFkN6n/Dy/FrDCe0QZidgQPEXkpVf0y/ntWx3Q7K1rhAlx 5BEf8fjJhENxnx5UV5M0qbq97pmtwPHFvpRQeE5IzH48PxMGP3Ab8WZJ2xuePUiZ6Onw Ye1xke/esOSF+y5CeCznPBHDdE1GIl8sWqHDKIwi5va1fDeY9eeZ4FLRGLNTxG0Gcx1o kWxw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1743456333; x=1744061133; 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=uVHNj+JtObElMyywTCHbfL1RCXVZFP608PFaksTvNto=; b=aPFEiwIZv8tekpS05JWHH4QWtAbQBFoYMFRoCGVUFscyPdbRJNqMPpCiaXuxe5n6J2 6Ap9XEC6f79OuigbEdvioeuL0pFaAs7a5J5SjWtEU2WpwWn7Gl88yc+UKUdD/EpbSlWu SWGXZuq10bNDw2NqqiXxAmtICyIgoDHuACeas8hq64OBFBQZss1T/me62l21XEbRhRIZ TcCw+a/bSnXi+s5hLmgyGuS58emfh37oxGYbM7JVM6J0N0VNHtk7lntNQyVU7nmCxVc3 HStJYIzpyQ4bNMcYBitDHKHd3apL+uhb+aWleWcCRHBs1W2+hautyPYr1wPiB75mGyyF 0yuw== X-Gm-Message-State: AOJu0YwhJte5yrx8roRYMapfyL2K+fNx/X9Cr1dG1oU+9HQyffXXyz2G oJmHVjkv1vcJOYHsVPYS4WNcJiLSOf+16UBkTPHdKrrCo0N4Fqk5/CNevu+sfnYF/1u3Hh/gKTe bk+g9JRZFu+I9gxHFxuJLDZmT660jl2pd X-Gm-Gg: ASbGnculDF8YOX8D7GhSTaLdYkTOb4BE/knzd4KBhZhehE+0k2NYP6mb2IvJZi5ivn7 0qUpepuB2TYkv/Zpro/qDSqTbaffOAHGUbqeZqR2KLK9Fj7z+xMBLEwTWK1BDoo233RpE/bE4iG CEYgWig9LX/E8jmq7sglNMWgTZFV2y+xskNE+QEjVvYKEWSdAW+Ev0WO/GnuM= X-Google-Smtp-Source: AGHT+IFbenMcWJrV7iZkqod8UMXLWiTWnvzdzNl8G9SFJm4dMkbGIiM/GuURFSkCGnVodQKxTDDW55R47UZmMo4h5Gc= X-Received: by 2002:a17:902:cecc:b0:215:89a0:416f with SMTP id d9443c01a7336-2295bea82b9mr6491725ad.30.1743456333273; Mon, 31 Mar 2025 14:25:33 -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: Mon, 31 Mar 2025 14:25:06 -0700 X-Gm-Features: AQ5f1JolRTi5NakuLy1BW9bJfV6vUYSd54GCd1tLM1H6q07vSqadO7-dEJCAAu4 Message-ID: Subject: Re: [PHP-DEV] [RFC] [Discussion] Never parameters To: Larry Garfield Cc: php internals Content-Type: multipart/alternative; boundary="0000000000006d24710631aa0f1e" From: matthewfonda@gmail.com (Matt Fonda) --0000000000006d24710631aa0f1e Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi Larry, On Fri, Mar 28, 2025 at 7:48=E2=80=AFPM Larry Garfield wrote: > I have to think people are misunderstanding Nikita's earlier comment, or > perhaps that he phrased it poorly. > > The determination of whether a method call is type-compatible with the > parameters passed to it is made *at runtime*, on the class. You can wide= n > a parameter type in an implementing class, and it will work. That's been > the case since PHP 7.4. > > For example: https://3v4l.org/5YPdg > > Even though the function is typed against I, if it's passed a C, you can > call it with a string. That's because C::a()'s param type is wider than > the interface. > > The idea of a never typed parameter is exactly the same: It starts off > super-narrow (accepts nothing), so implementations can accept anything > wider than "nothing" and still be type compatible. You *can* call it. > > What you cannot do is determine *statically* that it is callable, because > at static-analysis time, all you know is the interface. So SA tools won'= t > be able to verify that anything is valid for that interface. That's a > valid criticism of never params, I agree. Is it enough to vote against i= t > on those grounds? That's up to each voter to decide. > > But "you cannot ever even call it" is simply not true, unless there's som= e > weird engine limitation that I don't know about. > Correct, in saying you can't call it, we're referring to a static analysis perspective--or phrased differently, a "this is why interfaces exist and how you correctly use them" perspective. If we're writing code against an interface, the only thing we're "allowed" to do with a method is exactly what the interface specifies. If the interface specifies we can never call a method, then we can... never call it. In other words, we can't write code against the interface, so what's the point of the interface? It doesn't provide any extra safety. In fact, quite the opposite. Any code written against a method with a `never` parameter is inherently unsafe--it only works if we happen to pass the correct types at runtime. Widening from something (as opposed to widening from nothing, i.e. `never`) to something wider (e.g. `int` to `int|string` in your example) makes sense in a way that widening `never` does not. In this case, you have an actual type to begin with, so you can still write code against the interface. Continuing your example, if we're writing code against I::a(), the only thing we're "allowed" to do with it is call it with an int (otherwise the code may fail at runtime, e.g. https://3v4l.org/WUTv4). However, being able to widen here is still useful, because we can _also_ write code against C::a(), and in that context we're allowed to call with an int or a string. See https://3v4l.org/qMZOH. Contrast this to never parameters, where we were never able to write code against the interface. I'd argue that this is certainly grounds to vote against it--there's no point in using an interface if we can't write code against it. Best regards, --Matthew --0000000000006d24710631aa0f1e Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi= Larry,

On Fri, Mar 28, 2025 at 7:48=E2=80=AFPM Larry Garfield <larry@garfieldtech.com= > wrote:
I have to think people are misunderstanding Nikita's earlier comment, o= r perhaps that he phrased it poorly.=C2=A0

The determination of whether a method call is type-compatible with the para= meters passed to it is made *at runtime*, on the class.=C2=A0 You can widen= a parameter type in an implementing class, and it will work.=C2=A0 That= 9;s been the case since PHP 7.4.

For example: https://3v4l.org/5YPdg

Even though the function is typed against I, if it's passed a C, you ca= n call it with a string.=C2=A0 That's because C::a()'s param type i= s wider than the interface.

The idea of a never typed parameter is exactly the same: It starts off supe= r-narrow (accepts nothing), so implementations can accept anything wider th= an "nothing" and still be type compatible.=C2=A0 You *can* call i= t.

What you cannot do is determine *statically* that it is callable, because a= t static-analysis time, all you know is the interface.=C2=A0 So SA tools wo= n't be able to verify that anything is valid for that interface.=C2=A0 = That's a valid criticism of never params, I agree.=C2=A0 Is it enough t= o vote against it on those grounds?=C2=A0 That's up to each voter to de= cide.

But "you cannot ever even call it" is simply not true, unless the= re's some weird engine limitation that I don't know about.

Correct, in saying you can't call it, we= 9;re referring=C2=A0to a static analysis perspective--or phrased differentl= y, a "this is why interfaces exist and how you correctly use them"= ; perspective. If we're writing code against an interface, the only thi= ng we're "allowed" to=C2=A0do with a method is exactly what t= he interface specifies. If the interface specifies we can never call a meth= od,=C2=A0then we can... never call it. In other=C2=A0words, we can't wr= ite code against the interface, so what's the point of the interface? I= t doesn't provide any extra safety. In fact, quite the opposite. Any co= de written against a method with a `never` parameter is inherently unsafe--= it only works if we happen to pass the correct types at runtime.
=
Widening from something (as opposed to widening from nothing= , i.e. `never`) to something wider (e.g. `int` to `int|string` in your exam= ple) makes sense in a way that widening `never` does not. In this case, you= have an actual type to begin with, so you can still write code against the= interface. Continuing your example, if we're writing code against I::a= (), the only thing we're "allowed" to do with it is call it w= ith an int (otherwise the code may fail at runtime, e.g.=C2=A0https://3v4l.org/WUTv4). Howeve= r, being able to widen here is still useful, because we can _also_ write co= de against C::a(), and in that context we're allowed to call with an in= t or a string. See htt= ps://3v4l.org/qMZOH.

Contrast this to never pa= rameters, where we were never able to write code against the interface.

I'd argue that this is certainly grounds to vote = against it--there's no point in using an interface if we can't writ= e code against it.

Best regards,
--Matth= ew

--0000000000006d24710631aa0f1e--