On Mon, Apr 22, 2019, at 4:47 PM, Benjamin Morel wrote:
> Hi internals,
> 
> I'd like to revive an old discussion <https://externals.io/message/67131> 
> about
> object type casting.
> 
> The idea would be to allow (ClassName) casting:
> 
>     $service = (EmailService) $diContainer->get('email.service');
> 
> The above code would throw a TypeError if the value is not an instance of
> the given class. I see the following advantages:
> 
> - Type safety: we can be sure that the value is of the correct type or that
> we'll get an Error. This syntax allows to fail early if the variable
> happens to not be of the expected type, and avoids much more verbose checks;
> - Static analysis: IDEs and static code analysis tools can now understand
> the type of the variable, without having to resort to `@var` annotations.
> 
> These combine into a third advantage: readability. Today's equivalent of
> the above one-liner could be:
> 
>     /** @var EmailService $service */
>     $service = $diContainer->get('email.service');
>     if (! $service instanceof EmailService) {
>         throw new TypeError('Expected instance of EmailService, ...');
>     }
> 
> Which is a lot of boilerplate code that could be easily avoided by
> introducing this new syntax.
> 
> Before moving forward and working on a formal RFC, I'd like to hear your
> thoughts: what's your early feeling about this? Did I miss other
> discussions around this subject? Are there any technical issues that come
> to mind? Could this feature help the upcoming JIT compiler produce more
> efficient machine code by knowing the type of the variable at compile time?
> etc.
> 
> Note: "casting" might not be the perfect name here as what we're really
> doing is a type check, but this reuses the type casting syntax and
> resembles Java's object casting.
> 
> Thank you,
> Ben

Hi Ben.

First thought: I'm all for easy ways to be more type-explicit, so yay on the 
concept.

Second thought: That said, how many use cases for that are there other than 
function boundaries, which we already have covered?

I can think of two:  foreach() loops and returns where you know the return type 
with more specificity than the method you're calling.  Example:

/** @var Foo $foo *//
foreach ($arrayOfFoo as $foo) {
  $foo->bar();
}

Example from PSR-14, in which you know the object you're getting back MUST be 
the same one that's passed in but dispatch() has no return type:

/** @var Foo $event **/
$event = $dispatcher->dispatch(new Foo());

The second I can see being easily handled by this syntax.  The former, how 
would that look?

Third thought: Casting is the wrong name here, and feels also misleading as a 
syntax.  (float)$anInt means "type coerce this thing into a float", which 
cannot error.  You're suggesting (Foo)$bar to mean "if this isn't already a 
Foo, throw."  That's a very different behavior semantic for the same syntax.  
Is that a land mine?  I would expect (Foo)$bar to mean "recast $bar into an 
instance of Foo if possible, and error if not".  Which... I suppose "is it 
already" is a subcase of that, but it's still not the behavior I'd expect from 
that syntax.

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to