Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127562 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 lists.php.net (Postfix) with ESMTPS id 3CE151ADD3E for ; Tue, 3 Jun 2025 15:42:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1748965221; bh=zNqcbvjnYIgKe2ErrXL8BtHBiT8FoEZAdyl0zHY9QGo=; h=Date:To:From:Cc:Subject:In-Reply-To:References:From; b=nvyxRwrHHf/CYg0MMHm7/zsyahAsPvjdGxJtVtMR5V4wxvZtcGGjWQTNgld4ClIHa 0EytovmzIqVJPBR1yq7eot5iL04kYikCcLI5A3PO8WzXP4ks6EVXciGVwBIV7uPwXr +35Ap1x1/9X5SRYmdaZc80KFqatxgYNXoOl01UGn8fsO1+whsFqAcxRoNW6RAK53RA 7+Bc+kXWkYUZkQYI1mkQxu+SKJnrUAWsW+xO/9MbEm350sAO9zSSsjqUmjaXBKgPwe FvhO4bvqr9//OzH2i6NZPWcNG4z1pcoakZmGNn+NIkxyMBwNFgYzpx3pVe7vmJQdU3 mLMtTaFZmlVLQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 0841C180544 for ; Tue, 3 Jun 2025 15:40:19 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.2 required=5.0 tests=BAYES_40,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from mail-24420.protonmail.ch (mail-24420.protonmail.ch [109.224.244.20]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Tue, 3 Jun 2025 15:40:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gpb.moe; s=protonmail3; t=1748965339; x=1749224539; bh=zNqcbvjnYIgKe2ErrXL8BtHBiT8FoEZAdyl0zHY9QGo=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=LAn3VGgcom2RWsbJJGpseM0dsTwh08/iND2YwmPSmp0SkmuRYswi6Tg7SU4kC3Eo8 9d0GoIhelDLwZW5aC24aeumbDKfFS8NDxcxDA0VNjMmP9y/3G4n8VNvffcN3AKD4HP UHIXDSLsh0O/0M4u8fHcEDXZrU0MKl7gdbY/pxlHRy6GVHQpJLmWkZXaEJqCa9BpZ4 41FuyRpsYUVZQFu+HoodDFVkjd4ruVfq/AM6iDiZcnwVuUuQ46oGRlOAMimY5mMr4v B7XDJma49JAcX7RZTILgmomEPzyelE8L7z76wn3sWTQy9iJ8KuNjKSALOTrdbCrj1I zx00USRP5bo6g== Date: Tue, 03 Jun 2025 15:42:16 +0000 To: Ilija Tovilo Cc: PHP internals Subject: Re: [PHP-DEV] [RFC] Transform void into an alias for null Message-ID: <7yeVC5ZrSBpIklddJCWbIApB-mxRpBPasvWFIgoDeXZGXo_kbqdXAdNPEYoe0ajVjA1-P-w2d2JuDdYAN99BShDfnIPiuUqPuB_PbHEdeZ8=@gpb.moe> In-Reply-To: References: <6Z2Ysh6MjYp1nyzuB0bTPJc5srObIcMRqt731JaQeXUJk1f_V_Yo2nRn8WvjI7er7pp7pIUE6WYl5pRwvYrtcrd07nCutyAqKPSsZHmrS-Y=@gpb.moe> Feedback-ID: 96993444:user:proton X-Pm-Message-ID: d2a3f8b2554d91ef64bffcd613f6e65c7e46cc28 Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable From: internals@gpb.moe ("Gina P. Banyard") On Tuesday, 3 June 2025 at 00:48, Ilija Tovilo wro= te: > Hi Gina >=20 > On Mon, Jun 2, 2025 at 6:28=E2=80=AFPM Gina P. Banyard internals@gpb.moe = wrote: >=20 > > RFC: https://wiki.php.net/rfc/void-as-null >=20 >=20 > After a read, I think I fundamentally disagree with the proposal. It > says (regarding the status-quo): >=20 > > * void is not a subtype of a function with a mixed return type >=20 >=20 > This is laid out as a downside, but I don't think it is. Consider this > example under the specified behavior: >=20 > interface MapInterface { > public function set(string $key, mixed $value): void; > } >=20 > class Map implements MapInterface { > public function set(string $key, mixed $value): void { > // Store the key/value pair somehow > } > } >=20 > Let's assume the return type `MapInterface::set()` `mixed` instead, > where the intention is for `set()` to return the previous value, or > `null` if there was none. This change will go completely unnoticed by > `Map::set()`, because `void` is now just `null`, which is a subtype of > `mixed`. This is a bug that would previously have been caught, > notifying you that you're supposed to return something. >=20 > Similarly, the code `function foo(): void { return null; }` is now > proposed to be valid, and I assume the inverse for `void`/`return;` is > also true. In this example, we now update `Map::set()` to the new > return type. >=20 > class Map implements MapInterface { > public function set(string $key, mixed $value): mixed { > $oldValue =3D /* Fetch old value somehow */; > // Store the key/value pair somehow >=20 > if (!$this->observers) { >=20 > return; // This line was here before. > } >=20 > $this->observers->notify($key, $oldValue, $value); >=20 >=20 > return $oldValue; > } > } >=20 > Good examples are hard, but imagine `Map::set()` would allow notifying > a list of observers about changes to the map. Previously, the > `return;` would have prevented an erroneous call to `notify()` on > `null`. However, now it is missing the returning of `$oldValue`. This > is another bug that would previously have been caught. In fact, even a > missing trailing `return $something;` would not be caught anymore. >=20 > IMO, these checks are useful enough not to be removed. >=20 > Please let me know if I'm missing anything. I must say the examples are not really convincing to me. :) The compile time warning would *only* be suppressed for case where the retu= rn type of the function/method is *exactly* null or void, the moment you have a union type or mixed you would still get the compile t= ime error. I realise that I didn't properly describe the behaviour of my PoC implement= ation in the RFC, apologies for that. And a type system on its own is never going to be able to catch all impleme= ntation bugs, even with dependant and effect types, you can write code that passes a type= checker yet not do what is expected. A type system should be logical, and the fact that the top type (mixed) is = not a super-type of all types doesn't make any sense. We *specifically* included null within mixed as having a proper top type is= required, even if many people would have preferred it to exclude null and = just use ?mixed if you wanted "everything". As said to Anton, PHP does not have the concept/capability of "not returnin= g a value" (unless you throw/exit) Final small cheeky note, we don't warn/error in other cases where we detect= dead code, we let the optimizer get rid of them, is this something we shou= ld warn about? Best regards, Gina P. Banyard