Union type casts

php.internals

[ ]

3 years ago
Hello internals! I'm wondering if there are any plans for union type casts support. That's basically what I mean: ```php function checkItOut(int|float|string $bar) { $foo = (int|float)$bar; var_dump($foo); } ``` I assume the behavior should be the same as if we called the function having respective parameter type-hint (with a remark that strict types are disabled): ```php function checkItOut(int|float|string $bar) { $foo = cast($bar); var_dump($foo); } function cast(int|float $bar): int|float { return $bar; } ``` Best regards, Yevhen

Dusk

3 years ago
On Oct 4, 2022, at 21:46, Eugene Sidelnyk <zsidelnik@gmail.com> wrote:
> $foo = (int|float)$bar;
As written, I wouldn't know what to expect this to do with a string value -- would it cast it to int or float? Based on the behavior of your second example, the answer appears to be "float", so this syntax seems to be equivalent to: $foo = \is_int($bar) ? $bar : (float) $bar; Or, even more concisely: $foo = 0+$bar; I'd be even less sure what to expect when casting to other union types. What would the expected result of casting a string to (bool|array|object) be, for example? I'm not sure there are many meaningful operations which could be constructed here.

[ ]

3 years ago
As I mentioned before, it would work the same alike way as if we called function with such type-hint. FMPOV, one of the most meaningful use-cases would be nullable casts (like casting `?string` into `?float` for example). Regards, Yevhen On Wed, Oct 5, 2022, 8:41 AM Dusk <dusk@woofle.net> wrote:

Stephen Reay

3 years ago
> On 5 Oct 2022, at 12:41, Dusk <dusk@woofle.net> wrote: > > On Oct 4, 2022, at 21:46, Eugene Sidelnyk <zsidelnik@gmail.com> wrote: >> $foo = (int|float)$bar; > > As written, I wouldn't know what to expect this to do with a string value -- would it cast it to int or float? > > Based on the behavior of your second example, the answer appears to be "float", so this syntax seems to be equivalent to: > > $foo = \is_int($bar) ? $bar : (float) $bar; > > Or, even more concisely: > > $foo = 0+$bar; > > I'd be even less sure what to expect when casting to other union types. What would the expected result of casting a string to (bool|array|object) be, for example? I'm not sure there are many meaningful operations which could be constructed here. > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php >
Hi, I think the intention is that it would follow precisely the same casting rules as function parameters do. So e.g: ``` function foo(int|float $var) { return $var; } $f1 = foo(‘1’); $c1 = (int|float) ‘1’; $f2 = foo(‘1.1’); $c2 = (int|float) ‘1.1’; ``` In both scenarios the $f1/$c1 and $f2/$c2 would result in the same type. Your first example isn’t quite the same though; Passing ‘1’ to a parameter typed as `int|float` will cast it to an integer, your example casts such a value to a float. The `0+$value` thing is interesting, but also definitely seems less intuitive to my eye. Given your last comment I think its worth reiterating Eugene’s point is simply about exposing the **existing** cast behaviour that happens with typed parameters, to be usable on variables. I can see some benefit in the proposal, but I think I’d be more interested in the ability to define local variables as being a given type (or union), and then have the engine cast (or error) when assigning to them - essentially how typed object properties work, but for regular variables.

Claude Pache

3 years ago
> Le 5 oct. 2022 à 06:46, Eugene Sidelnyk <zsidelnik@gmail.com> a écrit : > > I assume the behavior should be the same as if we called the function > having respective parameter type-hint (with a remark that strict types are > disabled):
Hi, Function parameters are more restrictive than explicit cast in what it accepts. In particular, the following inputs are rejected with a TypeError when fed to a function that accepts an `int`: `"3 mices"`, `null`, `[ ]`. Most notably, no type conversion is performed when the input type is `null` or `array`, or when the target type is `array` or `object`. For reference, the original conversion rules are here: https://wiki.php.net/rfc/union_types_v2#coercive_typing_mode <https://wiki.php.net/rfc/union_types_v2#coercive_typing_mode> (I don’t know if there has been adjustments since then.) —Claude

juan carlos morales

3 years ago
There is a difference is declaring a function parameter of different types ... because before hand, when the code calls the function, we might not be sure about what kind if data the function will receive, so the function could expect different types, and work the parameter correctly internally..... nice but ... when casting, on purpose, what use case can apply to it? Are you facing a situation where manual union type cast is needed? can you share it with us? thanks

[ ]

3 years ago
I used to have an awkward feeling when it was necessary to convert the nullable integer into a nullable string. It would be kind of ternary operator anyway. Either `$b = (null !== $a) ? (string)$a : null;` or `$b = (string)$a ?: null;`. A lot easier to read would it be if written this way: `$b = (?string)$a;`. The intentions are clear when doing explicit type-cast. Currently, I don't see any other situations when this feature may be useful Thank you On Wed, Oct 5, 2022, 4:43 PM juan carlos morales <dev.juan.morales@gmail.com> wrote:

Marco Pivetta

3 years ago
On Wed, 5 Oct 2022 at 19:53, Eugene Sidelnyk <zsidelnik@gmail.com> wrote:
> I used to have an awkward feeling when it was necessary to convert the > nullable integer into a nullable string. It would be kind of ternary > operator anyway. Either `$b = (null !== $a) ? (string)$a : null;` or `$b = > (string)$a ?: null;`. > > A lot easier to read would it be if written this way: `$b = (?string)$a;`. > The intentions are clear when doing explicit type-cast. > > Currently, I don't see any other situations when this feature may be useful >
I don't think that this tiny edge case warrants a new language feature. I can endorse using [`azjezz/psl`]( https://github.com/azjezz/psl/blob/34391b78f097e7d489bd618d2cb15ef474937896/src/Psl/Type/TypeInterface.php#L21-L26) for this though: ```php use Psl\Type; $myValue = Type\union(Type\int(), Type\null()) ->coerce($input); ``` This will also throw an exception (**GOOD**) if the cast is not safe to perform. Marco Pivetta https://twitter.com/Ocramius https://ocramius.github.io/

Claude Pache

3 years ago
> Le 5 oct. 2022 à 19:53, Eugene Sidelnyk <zsidelnik@gmail.com> a écrit : > > I used to have an awkward feeling when it was necessary to convert the nullable integer into a nullable string. It would be kind of ternary operator anyway. Either `$b = (null !== $a) ? (string)$a : null;` or `$b = (string)$a ?: null;`. > > A lot easier to read would it be if written this way: `$b = (?string)$a;`. The intentions are clear when doing explicit type-cast. > > Currently, I don't see any other situations when this feature may be useful > > > Thank you
There has been some discussion and interest around nullable casting (which, contrarily to union type casting, has only one possible and obvious semantics), see https://wiki.php.net/rfc/nullable-casting <https://wiki.php.net/rfc/nullable-casting> and the two discussion threads linked in the bottom of the page. However, the RFC seems to be inactive for now, —Claude

Rowan Collins

3 years ago
On 5 October 2022 14:42:57 BST, juan carlos morales <dev.juan.morales@gmail.com> wrote:
>Are you facing a situation where manual union type cast is needed?
I can't think of any examples for full union types off the top of my head, but nullable casts would frequently be useful, e.g. when you have a value that is either a numeric string or null, and you want an integer, but for null to stay null, not become zero. There's also a slightly different case, where you want values which aren't numeric to also become null. As I commented on another thread, this is a space I've been thinking about recently, and it gets complicated quickly. Regards,
-- Rowan Tommins [IMSoP]