Hi Larry, thanks for the early feedback!

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

Glad to hear that!

> Second thought: (...) how many use cases for that are there other than
function boundaries, which we already have covered?

I chose an example where function boundaries are typically not covered:
dependency injection containers, which have some generic `get()` method
that can return any type.
Another one is ORMs: Doctrine's EntityManager::find(), for example, returns
a generic `object`.

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

I guess it could be used this way:

    foreach ($arrayOfFoo as $foo) {
        ((Foo) $foo)->bar();
    }

Although this use case is not the primary motivation for this feature,
which is not meant to replace all object type hints.

> Third thought: Casting is the wrong name here, and feels also misleading
as a syntax.

I suspected this would come up, hence the final note; I'm open to
suggestions for alternatives. Please note that Java's object casting uses
the same syntax, and follows the same semantics of
throw-if-not-instance-of. The difference, if I'm not mistaken, is that you
can type-hint an object to more generic interface or parent class, or, on
the contrary, type-hint it to a more specific sub-class or concrete class
to make its members accessible; this part is obviously not needed in PHP as
the VM does not care what the type is before attempting to access one of
its members. But I'm not sure if the fact that we miss the "conversion"
part is enough to justify a change in naming or syntax compared to the Java
equivalent?

- Ben


On Tue, 23 Apr 2019 at 00:03, Larry Garfield <la...@garfieldtech.com> wrote:

> 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