Re: [PHP-DEV] Type casting syntax

This is only part of a thread. view whole thread
  115407
July 12, 2021 14:26 internals@lists.php.net ("Levi Morrison via internals")
On Sun, Jul 11, 2021 at 5:19 PM Larry Garfield <larry@garfieldtech.com> wrote:
> > On Sun, Jul 11, 2021, at 5:30 PM, Levi Morrison via internals wrote: > > I like Rust's From and TryFrom traits, which allow types to define > > conversions into or from other types. The From trait always succeeds, > > and TryFrom can fail. However, it's not a "cast" -- the user calls an > > `into`/`try_into` or `from`/`try_from` methods. > > > > I would be supportive of defining official ways to convert types from > > one to another, not necessarily casts, though. I think these qualities > > are important: > > > > 1. Would have failable and non-failable variants. It's nice to know > > that a particular conversion cannot or can fail. > > 2. It should be amenable to static analysis. Tools should be able to > > warn about missing paths for handling failable conversions, or that > > conversion from A to B is possible but A to C is not. > > > > I'm not sure how to technically achieve this for PHP. I don't think > > any casting proposal I've seen meets these characteristics, so I would > > personally vote no on them. > > What are the use cases for integrated object to object (ie, class to class) conversion in PHP? Rust's type system is a very different beast, so its casting logic makes more sense there. I'm not entirely clear on what the use case is in PHP. When would that be superior to "just write an asFoo() method and move on with life"? > > Scalar conversion I can see, but every time someone suggests adding siblings to __toString(), there's major pushback. > > --Larry Garfield > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php >
The features I was referring to are not casting; casting does exist in Rust but this is not it. Rather, it's a generic way to convert objects. It's nice to have a standard way to do it, instead of every project doing something bespoke. It also can enable some use cases that aren't relevant in PHP (yet) such as taking any generic type which can be converted into a T, because you only want to do that transformation conditionally on something else.
  115410
July 12, 2021 15:00 larry@garfieldtech.com ("Larry Garfield")
On Mon, Jul 12, 2021, at 9:26 AM, Levi Morrison via internals wrote:

> > What are the use cases for integrated object to object (ie, class to class) conversion in PHP? Rust's type system is a very different beast, so its casting logic makes more sense there. I'm not entirely clear on what the use case is in PHP. When would that be superior to "just write an asFoo() method and move on with life"? > > > > Scalar conversion I can see, but every time someone suggests adding siblings to __toString(), there's major pushback. > > > > --Larry Garfield > > > > -- > > PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: https://www.php.net/unsub.php > > > > The features I was referring to are not casting; casting does exist in > Rust but this is not it. Rather, it's a generic way to convert > objects. It's nice to have a standard way to do it, instead of every > project doing something bespoke. It also can enable some use cases > that aren't relevant in PHP (yet) such as taking any generic type > which can be converted into a T, because you only want to do that > transformation conditionally on something else.
So, like David suggested, some standardized version of $foo->as($type), which then returns an instance of $type? I... don't think I've ever done that often enough to justify a standard feature for it. When have you run into it? That also seems quite different from what Max is talking about: On Mon, Jul 12, 2021, at 9:54 AM, Max Semenik wrote:
> I was thinking of something akin to many compiled languages' approach of > "consider this expression is now of that type, and throw an exception if > it's not". An example of this approach from Benjamin's proposal of old^ > > $service = (EmailService) $diContainer->get('email.service'); > > Instead of > > /** @var EmailService $service */ > $service = $diContainer->get('email.service'); > if (!$service instanceof EmailService) { > throw new TypeError('Expected instance of EmailService, ...'); > }
Hm, that's a different creature. I... would be probably OK with something in that direction, though I wouldn't work on it myself. I think what you're describing here is more of a type assertion. "Assert that this variable is of type X, otherwise bail." So, some kind of non-disableable (or maybe disableable?) shorthand for `assert($foo instanceof Bar)`. --Larry Garfield
  115412
July 12, 2021 17:01 mike@newclarity.net (Mike Schinkel)
> On Jul 12, 2021, at 11:00 AM, Larry Garfield <larry@garfieldtech.com> wrote: > x > On Mon, Jul 12, 2021, at 9:54 AM, Max Semenik wrote: > >> I was thinking of something akin to many compiled languages' approach of >> "consider this expression is now of that type, and throw an exception if >> it's not". An example of this approach from Benjamin's proposal of old^ >> >> $service = (EmailService) $diContainer->get('email.service'); >> >> Instead of >> >> /** @var EmailService $service */ >> $service = $diContainer->get('email.service'); >> if (!$service instanceof EmailService) { >> throw new TypeError('Expected instance of EmailService, ...'); >> } > > Hm, that's a different creature. I... would be probably OK with something in that direction, though I wouldn't work on it myself. I think what you're describing here is more of a type assertion. "Assert that this variable is of type X, otherwise bail." So, some kind of non-disableable (or maybe disableable?) shorthand for `assert($foo instanceof Bar)`.
Regarding prior art on type assertion, the syntax Go uses is `value.(type)` so using a similar approach in PHP might look like this (I'm spitballing by using the double colon as a sigil but it could anything that doesn't conflict with existing usage, whatever those options are): $service = $diContainer->get('email.service')::(EmailService); Additionally in Go a type assertion can return a second value which is boolean telling if the type assertion succeeded. Not having this would effectively moot the benefit to a type assertion if you had to wrap with try{}catch{} in case it failed. $service, $okay = $diContainer->get('email.service')::(EmailService); if (!$ok) { echo 'Not an EmailService.'; } #fwiw -Mike
  115413
July 12, 2021 17:56 maxsem.wiki@gmail.com (Max Semenik)
On Mon, Jul 12, 2021 at 8:01 PM Mike Schinkel <mike@newclarity.net> wrote:

> Additionally in Go a type assertion can return a second value which is > boolean telling if the type assertion succeeded. Not having this would > effectively moot the benefit to a type assertion if you had to wrap with > try{}catch{} in case it failed. >
Not necessarily: if ($obj instanceof MyClass) { // We know its type here } else { // Try something else } -- Best regards, Max Semenik
  115415
July 12, 2021 20:20 mike@newclarity.net (Mike Schinkel)
> On Jul 12, 2021, at 1:56 PM, Max Semenik wiki@gmail.com> wrote: > > On Mon, Jul 12, 2021 at 8:01 PM Mike Schinkel <mike@newclarity.net <mailto:mike@newclarity.net>> wrote: > Additionally in Go a type assertion can return a second value which is boolean telling if the type assertion succeeded. Not having this would effectively moot the benefit to a type assertion if you had to wrap with try{}catch{} in case it failed. > > Not necessarily: > > if ($obj instanceof MyClass) { > // We know its type here > } else { > // Try something else > }
Well there you go. It seems you have just illustrated why in reality we really do not need type casting/assertions in PHP given its current features, because we already have what we need. -Mike
  115416
July 12, 2021 20:28 kjarli@gmail.com (Lynn)
On Mon, Jul 12, 2021 at 10:20 PM Mike Schinkel <mike@newclarity.net> wrote:

> It seems you have just illustrated why in reality we really do not need > type casting/assertions in PHP given its current features, because we > already have what we need. >
That's not an argument I agree with, as it would invalidate the need for short closures, null coalesce, constructor property promotion, etc. Continuing on the previous example: ```php $service = $container->get(SomeService::class); assert($service instanceof SomeService); // could be replaced with $container->get(); // or in case of multiple instances: $container->get('the.service.alias'); // perhaps the service is optional $container->get(); ```
  115417
July 12, 2021 20:36 mike@newclarity.net (Mike Schinkel)
> On Jul 12, 2021, at 4:28 PM, Lynn <kjarli@gmail.com> wrote: > On Mon, Jul 12, 2021 at 10:20 PM Mike Schinkel <mike@newclarity.net <mailto:mike@newclarity.net>> wrote: > It seems you have just illustrated why in reality we really do not need type casting/assertions in PHP given its current features, because we already have what we need. > > That's not an argument I agree with, as it would invalidate the need for short closures, null coalesce, constructor property promotion, etc. > > Continuing on the previous example: > ```php > $service = $container->get(SomeService::class); > assert($service instanceof SomeService); > > // could be replaced with > $container->get();
In your hypothetical view here, what happens when the $container does not have SomeService to provide? Does it throw an Exception? -Mike
  115419
July 12, 2021 21:16 kjarli@gmail.com (Lynn)
On Mon, Jul 12, 2021 at 10:36 PM Mike Schinkel <mike@newclarity.net> wrote:

> > In your hypothetical view here, what happens when the $container does not > have SomeService to provide? Does it throw an Exception? > > Up to the developer that implements it. If the signature would be
`get(?string $id): T;` then I would assume an error should be thrown by PHP, or an Exception by the method, or handled by the developer to always return `T`. `?SomeException` as `T` could let the developer not throw an exception if needed and return `null` instead.
  115418
July 12, 2021 21:00 maxsem.wiki@gmail.com (Max Semenik)
On Mon, Jul 12, 2021 at 11:20 PM Mike Schinkel <mike@newclarity.net> wrote:

> It seems you have just illustrated why in reality we really do not need > type casting/assertions in PHP given its current features, because we > already have what we need. >
Heh, nope - you asked for handling of such cases without exceptions, I obliged. My plans were around different usage scenarios. In any case, I'm not making a proposal at this point, I'm just enquiring about syntax. If I ever get something proposable done, I'll make a formal RFC. -- Best regards, Max Semenik