On 21/03/2024 19:03, Robert Landers wrote:
I suppose we are taking this from different viewpoints, yours appears
to be more of a philosophical one, whereas mine is more of a practical
one.


My main concern is consistency; which is partly philosophical, but does have practical impact - the same syntax meaning the same thing in different contexts leads to less user confusion and fewer bugs.

But I also think there are real use cases for "error on anything other than either Foo or null" separate from "give me a null for anything other than Foo".

$x = $a as null;

(or any other value, such as true|false) appears to have no practical
purpose in this particular case.


There's plenty of possible pieces of code that have no practical purpose, but that on its own isn't a good reason to make them do something different.

"null" as a standalone type (rather than part of a union) is pretty much always pointless, and was forbidden until PHP 8.2. It's now allowed, partly because there are scenarios involving inheritance where it does actually make sense (e.g. narrowing a return type from Foo|null to null); and probably also because it's easier to allow it than forbid it.


That's not really what we're talking about anyway, though; we're talking about nullable types, or null in a union type, which are much more frequently used.



Further, reading "$x =
$a as null", as a native English speaker, appears to be the same as
"$x = null".


Well, that's a potential problem with the choice of syntax: "$x = $a as int" could easily be mistaken for "cast $a as int", rather than "assert that $a is int".

If you spell out "assert that $a is null", or "assert that $a is int|null", it becomes very surprising for 'hello' to do anything other than fail the assertion.


As I mentioned in the beginning, I see this mostly being used when
dealing with mixed types from built-in/library functions, where you
have no idea what the actual type is, but when you write the code, you
have a reasonable expectation of a set of types and you want to throw
if it is unexpected.


My argument is that you might have a set of expected types which includes null, *and* want to throw for other, unexpected, values. If "|null" is special-cased to mean "default to null", there's no way to do that.


Right now, the best way to do that is to simply
set a function signature and pass the mixed type to the function to
have the engine do it for you


And if you do that, then a value of 'hello' passed to a parameter of type int|null, will throw a TypeError, not give you a null.

As I illustrated in my last e-mail, you can even (since PHP 8.2) have a parameter of type null, and get a TypeError for any other value. That may not be useful, but it's entirely logical.


It makes more sense, from a practical programming
point-of-view, to simply return the value given if none of the types
match.

This perhaps is a key part of our difference: when I see "int|bool|null", I don't see any "value given", just three built-in types: int, which has a range of values from PHP_INT_MIN to PHP_INT_MAX; bool, which has two possible values "true" and "false"; and null, which has a single possible value "null".

So there are 2**64 + 2 + 1 possible values that meet the constraint, and nothing to specify that one of those is my preferred default if given something unexpected.


Regards,

--
Rowan Tommins
[IMSoP]

Reply via email to