@Nikita Popov nikita.ppv@gmail.com
It's not possible to use (ClassName) as a cast syntax, because it is
ambiguous.
Aw. I did not think about a possible conflict here, thanks for bringing
this up!
@Stephen Reay php-lists@koalephant.com
My objection to as
is that it specifically prevents (or makes very
confusing) the foreach
use I mentioned. There’s no variables involved in
imports/traits, and neither of those relates to foreach.
I'm sorry, I still don't understand what the issue with foreach is? As I
said before, the proposed syntax does not aim to be used inside the foreach
() parentheses, but rather as an explicit declaration inside the foreach {}
block.
As for the string $foo = $bar->getFoo();
‘looking strongly typed’ and
wondering if it will allow re-declaration - do you think the same when you
see function (string $foo) { $foo = explode(‘ ‘, $foo); }
? Functions
have allowed type hints since 5.0 - nearly 15 years ago, and nobody seems
to be confused if those variables can be redeclared. Whether you should
redeclare them to a different value is something you need to decide for
yourself.
You have a point. I can't say why, but outside of the function declaration,
it looks more like a static typing to me (and someone else had the same gut
reaction earlier in this thread). I may just be plain wrong.
As for limiting this to class/interface names - why would you do that? It
took YEARS to get scalar type hints for function parameters, why would you
not include them from the start on anything new that pertains to
essentially the same functionality?
I'm definitely not against supporting other types, it's just that the
original syntax I had in mind was using () casting, which was already
covered for other types.
Now if people like Hack's as
syntax, it would probably make sense to
generalize it indeed.
@Dan Ackroyd Danack@basereality.com
Similar to the nullable casting idea, you're taking a problem caused
by your own code/framework, and then thinking it should be solved in
core, when a simple solution is available in user-land.
...
btw I'm sure you're already aware of it, but this is using a
'dependency injector' as a service locator. If your current DI library
isn't powerful enough for you, rather than abusing it like this,
I think that the sudden focus on the specific case of DI container /
service locator reveals a misunderstanding here. The example I chose is
obviously responsible for that and this choice was perhaps infortunate: it
didn't help convey the true meaning of the proposal.
As I said earlier, I'm a heavy user of Dependency Injection AND Inversion
of Control; my framework does not suffer from any such limitation: my
controllers' and services' dependencies are explicitly declared and
injected automatically, and no such code relies on fetching dependencies
from the container directly. These classes are not even aware of the
existence of the container, and not tied to the DI framework in any way.
Also, my repositories are full blown, and encapsulate the ORM to return
specific entities.
YET, I also do some quick prototypes or CLI scripts that would not benefit
from too much boilerplate, and may use the DI container or the ORM's entity
manager directly. I also get objects from various losely typed data sources
(functions returning mixed types, arrays, iterators of all sorts, etc.)
that I expect to be of a given type, and that would benefit from the
added readability,
type checking and static analysis capabilities the current proposal offers.
@Andrey Hristov php@hristov.com
this is easily solvable with the following (considering strict_types is
enabled)
function tostr(string $in) : string { return $in; }
This solves it for a single type, but you have to write a function for
every class you want to enforce:
function toEmailService(EmailService $service) : EmailService { return
$service; }
function toUser(User $user) : User { return $user; }
As you can see, this gets ugly real quick. Your IDE and/or static analysis
tool will also probably warn about "Expecting Foo, got mixed", whereas with
an explicit cast/enforced-type-hint, the tooling would know that you're
explicitly stating that this unknown typed value is an instance of Foo.
Hi,
Hello Dan,
I don' think this a problem relating to just one use case, some PHP
builtin functions have weird union return types, where static analysis
tools would warn you about the return type being string|bool
, when you
are expecting string
.
using type constrain :
$foo = substr($foo, 1, 3) as string;
// there's no need to check if `$foo` is false here.
this is easily solvable with the following (considering strict_types is
enabled)
function tostr(string $in) : string { return $in; }
$foo = tostr($foo);
Put it in a convenience namespace and that's it.
Cheers,
Andrey
Cheers,
Sent with ProtonMail Secure Email.
‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
On Tuesday, April 23, 2019 11:33 AM, Dan Ackroyd Danack@basereality.com
wrote:
HI Benjamin,
Similar to the nullable casting idea, you're taking a problem caused
by your own code/framework, and then thinking it should be solved in
core, when a simple solution is available in user-land.
If you changed what you currently have:
$service = $diContainer->get('email.service');
to also take the expected class:
$service = $diContainer->get('email.service', EmailService::class);
And then check inside your 'DI container' whether the expected type is
returned, this solves the problem without needing new syntax.
btw I'm sure you're already aware of it, but this is using a
'dependency injector' as a service locator. If your current DI library
isn't powerful enough for you, rather than abusing it like this, I'd
recommend looking at a different one, like
https://github.com/rdlowrey/Auryn
Also, similar:
By the way, this RFC is a special case of something that could be far
more generic. If it was possible to register callbacks to be used when
casting, ...
Apparently this might not be possible as it's ambiguous....which is a
shame.
cheers
Dan
Ack
On Mon, 22 Apr 2019 at 22:47, Benjamin Morel benjamin.morel@gmail.com
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