Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:117707 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 74325 invoked from network); 9 May 2022 21:23:47 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 9 May 2022 21:23:47 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id D850B18004E for ; Mon, 9 May 2022 16:02:22 -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,HTML_MESSAGE,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE 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-wr1-f44.google.com (mail-wr1-f44.google.com [209.85.221.44]) (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, 9 May 2022 16:02:22 -0700 (PDT) Received: by mail-wr1-f44.google.com with SMTP id v12so21355345wrv.10 for ; Mon, 09 May 2022 16:02:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=craigfrancis.co.uk; s=default; h=from:message-id:mime-version:subject:date:in-reply-to:cc:to :references; bh=b5igFMbwe1OvqHX9Qu38wqyxMe4BJjLnZmyOs898BZQ=; b=AbrsVJpY/iR4SgbGSq8bkyXoqvElHC0MkIEugjRpM3b8VrNA0yXLKE3zPrhnRd+dBj mebYbapWvaMx0nTrycotz7rq939Y1TSR2clI4TYgIxxt1mfiLRhv63xE54X+EXqLOKU1 GqoYuMhEPuQBz+0zL+LnYiWo7wRXtwHAC/Om4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:message-id:mime-version:subject:date :in-reply-to:cc:to:references; bh=b5igFMbwe1OvqHX9Qu38wqyxMe4BJjLnZmyOs898BZQ=; b=G9RZ7ltalF3uxuHbxsQvsqkg2D/XCfz0cjSVw/Z1BLJnFroTtEHRidW12Tmng7d4kO OUvOrmB3Kbp8an5iCbYU/hbj1ujlJ7jA7o4GBbEv5D7lAtFdLiirUDs7uNglwns/FMHU LaG5yUpyjDmlTD7GEUtnCMu9gyPUZ1ZYrx8SCPcr48Gy9wL/JVW2T4aak1oHQ67WV8B9 oB+rm7F8IJJZC4TfmHKZH50qGqb7WbWidTu2YIlewzflcXwRmXEE+j8UeW6ygBpKFVjz Uod/FzyhQf0kg4d6G2i74/YdYpb9QkpDf9gcC9owiTS9tRQXBxrf6k4j+Yy0niZKBiv5 eLog== X-Gm-Message-State: AOAM532CRHNOvBiarx1IVj7i7DM4d+jWQQgiLBkUUMlz2LnD8+Fi9oWG KtQP35e1L39DeytjFaGf2W9Iyw== X-Google-Smtp-Source: ABdhPJwZibu9guDWrcfohTCC+PFz5881Gx7aOBHRtTRNj4Ka7P3j6R005hIz2267oXkxhSZ6udx/cA== X-Received: by 2002:a5d:62cc:0:b0:20c:d4f5:dea9 with SMTP id o12-20020a5d62cc000000b0020cd4f5dea9mr1218249wrv.141.1652137340858; Mon, 09 May 2022 16:02:20 -0700 (PDT) Received: from smtpclient.apple ([94.173.138.98]) by smtp.gmail.com with ESMTPSA id ay13-20020a5d6f0d000000b0020c5253d8dcsm13084769wrb.40.2022.05.09.16.02.19 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 May 2022 16:02:19 -0700 (PDT) Message-ID: <5D843EFA-B0D1-4CF5-AB1B-0E6F224D7119@craigfrancis.co.uk> Content-Type: multipart/alternative; boundary="Apple-Mail=_D52FE706-F3B4-4A6D-AA9C-B92CEB2DF0A2" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3696.80.82.1.1\)) Date: Tue, 10 May 2022 00:02:18 +0100 In-Reply-To: Cc: PHP internals To: Jordan LeDoux References: X-Mailer: Apple Mail (2.3696.80.82.1.1) Subject: Re: [PHP-DEV] NULL Coercion Consistency From: craig@craigfrancis.co.uk (Craig Francis) --Apple-Mail=_D52FE706-F3B4-4A6D-AA9C-B92CEB2DF0A2 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii On 7 May 2022, at 22:11, Jordan LeDoux wrote: > On Sat, May 7, 2022 at 1:38 AM Craig Francis > wrote: >=20 > Not what I'm going for... but anyway, to get an idea of your position, = do you think the string '15' should be coerced to a number, or should it = fatal error as well? e.g. >=20 > $my_number =3D round($request->get('my_number')); >=20 >=20 > '15' is not an undefined value. >=20 > If a program uses the paradigm that null represents the equivalent of = something like `unset($var)` Hi Jordan, Some programers can do that, but it's not how everyone sees it. NULL is not the same as `unset()`, it is a value in itself, and many = programmers simply give no thought to the distinction between an Empty = String and NULL. e.g. when using the noted frameworks, NULL is provided = for user values, and developers will often treat it the same as an Empty = String... if `$name =3D=3D ''`, then show an error saying your name is = required; if `strlen($name) > 200` then your name is too long, etc. > What exactly would be the purpose of `?int` if this RFC was passed? To = pass the value as null instead of 0? I'll talk about `int` below; but just so I can focus on the nullability = part of this question, I'll use `?string`... Yes, that's all I'm proposing. For example `?string` would not change (it will continue to provide the = NULL value to the function), whereas `string` would coerce NULL to an = Empty String, e.g. ``` function accept_nullable_string(?string $my_string) { var_dump($my_string); } function accept_string(string $my_string) { var_dump($my_string); } accept_nullable_string(3); // string(1) "3" accept_nullable_string('2'); // string(1) "2" accept_nullable_string(true); // string(1) "1" accept_nullable_string(false); // string(0) "" accept_nullable_string(NULL); // NULL accept_string(3); // string(1) "3" accept_string('2'); // string(1) "2" accept_string(true); // string(1) "1" accept_string(false); // string(0) "" accept_string(NULL); // Currently TypeError, change to string(0) "" ``` > That's it? Yep, but the point is about avoiding the upgrade problem when internal = functions will stop coercing NULL, and instead throw type errors (these = are hard to find, and will break code in seemly random places). > What about `int|float`? Which one would it be coerced to? Good question, Short answer; today, if you pass the string '4' to a function that uses = `int|float`, then it receives `int(4)`: ``` function accept_number(int|float $my_int) { var_dump($my_int); } accept_number('4'); // int(4) ``` Longer answer... First I'll note the documentation says (for string to integer = conversion) "If the string is numeric or leading numeric then it will = resolve to the corresponding integer value, otherwise it is converted to = zero (0)." = https://www.php.net/manual/en/language.types.integer.php#language.types.in= teger.casting = But an Empty String is not coerced to `int(0)` for user defined = functions, or arithmetic (e.g. `5 + ""` complains after PHP 7.1)... = whereas, an empty string is converted to 0 when using `intval($var)`, = and `(int) $var`. While I think this can be a bit harsh, I can see how it might avoid some = ambiguity/issues, e.g. `$offset =3D ''; $a =3D substr('abc', $offset)`, = although I have seen `substr('abc', NULL, $length)` a few times. If PHP was to throw an exception for NULL to integer coercion with = internal functions, while I recognise this would still create a BC break = (e.g. `round($nullable)`), I'd might be fine with it, because an Empty = String to Integer is also rejected. That said, and back to your question about `int|float`, because the = string '4' is coerced to `int(4)`, I'd prefer NULL to be coerced to = `int(0)`. > This pretty radically changes how typing itself would work in existing = user programs. I wouldn't say this is radical, considering it's just removing a single = type error (I suspect it's rare for code to rely on NULL coercion = triggering an exception)... in contrast, internal functions have always = worked with null coercion, and works in other contexts like string = concatenation (`'A' . $nullable`), =3D=3D comparisons, the = print()/echo() functions, etc. > What I'm saying is that for such a radical BC break you need to = provide some compelling justification, and I'm concerned from your = replies in this thread and the content of the RFC that you don't = actually understand the extent of a BC-break you're proposing. As noted previously, and the example I've added to the "Backward = Incompatible Changes" section, I don't think this is a radical BC break, = it's fairly small change designed to make NULL coercion work as = documented, in a constant way (all contexts), and most importantly, = avoid the upgrade problems for PHP 9.0 (please keep in mind the lack of = tooling to help with this, where the only safe and easy way to handle = this would be to add NULL coalescing throughout the code base, which is = not a good idea). Craig --Apple-Mail=_D52FE706-F3B4-4A6D-AA9C-B92CEB2DF0A2--