I've felt the need for this for some time.
Proposed syntax:
$x = (InterfaceName) $container->service;
Proposed behavior:
Checks if the instance if an instance of the given class/interfaces. If yes, does nothing, if not, issues a fatal error. Pseudo code:
$temp = $container->service;
if ($temp instanceof InterfaceName) {
$x = $temp;
} else {
trigger_error('The object can not be cast to InterfaceName');
}
Use cases:
As my example hints, the intent is to provide type safety and hinting for the increasingly used dependency injection container pattern.
It's useful to provide type safety also for all similar patterns which may not return a result of the expected type: Registry, ServiceLocator, Factory etc.
Additionally to runtime type safety, this will also serve to editors/IDEs as an inline hint to provide proper autocompletion, i.e. instead of this:
/** @var $foo InterfaceName */
$foo = $container->service;
People can now just write:
$foo = (InterfaceName) $container->service;
Alternative syntax:
I realize "casting" isn't a perfect match as the behavior is equivalent to inline type hinting. On the other hand, casting and inline type hinting in dynamic languages often behave identically (see the casting behavior in ActionScript which combines type hints with a JS-like dynamic type system).
And this syntax doesn't introduce new keywords. Still, alternative ways to implement this could be:
- $foo = $container->service as InterfaceName;
- $foo = $container->service is InterfaceName;
- $foo = (InterfaceName $container->service);
- InterfaceName $foo = $container->service;
All of those would be fine, especially 4, which has precedent in other languages, and in PHP as well with typehinting and in catch blocks: catch (ClassName $e) { ... }
I'm ok with suggestions for any syntax that is as short, if it fits the behavior better.
Feedback?
Stan
I've felt the need for this for some time.
Proposed syntax:
$x = (InterfaceName) $container->service;
Proposed behavior:
Checks if the instance if an instance of the given class/interfaces. If
yes, does nothing, if not, issues a fatal error. Pseudo code:$temp = $container->service;
if ($temp instanceof InterfaceName) {
$x = $temp;
} else {
trigger_error('The object can not be cast to InterfaceName');
}Use cases:
As my example hints, the intent is to provide type safety and hinting for
the increasingly used dependency injection container pattern.It's useful to provide type safety also for all similar patterns which may
not return a result of the expected type: Registry, ServiceLocator, Factory
etc.Additionally to runtime type safety, this will also serve to editors/IDEs
as an inline hint to provide proper autocompletion, i.e. instead of this:/** @var $foo InterfaceName */
$foo = $container->service;People can now just write:
$foo = (InterfaceName) $container->service;
Alternative syntax:
I realize "casting" isn't a perfect match as the behavior is equivalent to
inline type hinting. On the other hand, casting and inline type hinting in
dynamic languages often behave identically (see the casting behavior in
ActionScript which combines type hints with a JS-like dynamic type system).And this syntax doesn't introduce new keywords. Still, alternative ways to
implement this could be:
- $foo = $container->service as InterfaceName;
- $foo = $container->service is InterfaceName;
- $foo = (InterfaceName $container->service);
- InterfaceName $foo = $container->service;
All of those would be fine, especially 4, which has precedent in other
languages, and in PHP as well with typehinting and in catch blocks: catch
(ClassName $e) { ... }I'm ok with suggestions for any syntax that is as short, if it fits the
behavior better.Feedback?
Stan
I actually like the (InterfaceName) casting approach. I can see how type
casting as an object instance could lead to all sorts of innovative coding
architectures. I'm less enthused about the 4 alternatives you mentioned,
though. But overall I think it's a pretty awesome idea.
--Kris
I've felt the need for this for some time.
Proposed syntax:
$x = (InterfaceName) $container->service;
I'm against this. Let's be honest, how different is this that an
optionally static type?
InterfaceName $x = $container->service;
To be clear, I WANT optionally static typing. For the most part,
type-hinting in class methods solves the static typing needs, but if
we were able to declare a class member to be a certain type that would
be another significant improvement. I have a proposal in the works,
but I don't want to hijack your thread.
To sum up: I think we need something LIKE what you are proposing, but
I'm against this particular proposal.
Proposed syntax:
$x = (InterfaceName) $container->service;
I'm against this. Let's be honest, how different is this that an
optionally static type?InterfaceName $x = $container->service;
To be clear, I WANT optionally static typing. For the most part,
type-hinting in class methods solves the static typing needs, but if
we were able to declare a class member to be a certain type that would
be another significant improvement. I have a proposal in the works,
but I don't want to hijack your thread.To sum up: I think we need something LIKE what you are proposing, but
I'm against this particular proposal.
What you want is option 4 under my alternative syntaxes section :)
I'm ok with syntax 4, in fact, the more I think about it, the more I prefer
that one (the one you want).
I don't mind the syntax as much, I want the feature.
Stan
Levi,
On Tue, Aug 14, 2012 at 9:51 AM, Levi Morrison morrison.levi@gmail.comwrote:
I've felt the need for this for some time.
Proposed syntax:
$x = (InterfaceName) $container->service;
I'm against this. Let's be honest, how different is this that an
optionally static type?InterfaceName $x = $container->service;
To be clear, I WANT optionally static typing. For the most part,
type-hinting in class methods solves the static typing needs, but if
we were able to declare a class member to be a certain type that would
be another significant improvement. I have a proposal in the works,
but I don't want to hijack your thread.To sum up: I think we need something LIKE what you are proposing, but
I'm against this particular proposal.
I agree with you. The one case where this syntax may be very useful is if
we want to implement class casting. So introduce a pair of magic methods
public function __castToClass($class) {
}
public static function __castFromScalar($scalar) {
}
Then,
$foo = (A) $objectExtendingFromA; // No-op
$foo = (A) $objectNotFromA; // Calls $objectNotFromA->__castToClass('A'),
and if it returns something that matches A, good, if not fail
$foo = (A) 1; // Calls A::__castFromScalar(1);
Now, note that it would only work on class names, as doing it on interfaces
would only work in the objectNotFromA case (and even then, it would be
weird).
Now, I'm just saying that this is the only way I'd want to see something
like this. The use cases for it are there, but extremely narrow and likely
better solved with other mechanisms. So I'm not completely sure I like the
concept as a whole, but just throwing it out there...
Anthony
Hi!
I agree with you. The one case where this syntax may be very useful is if
we want to implement class casting. So introduce a pair of magic methods
I do not think we want to implement class casting. I'm not sure how
class casting even makes sense - if the object is of one class, how can
you just make it into another class by casting? If you mean "casting"
actually returns another object of different class, then just make a
method for that that returns that object, I do not see how obscuring the
purpose of this operation with unobvious syntax would help.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi!
I agree with you. The one case where this syntax may be very useful is if
we want to implement class casting. So introduce a pair of magic methodsI do not think we want to implement class casting. I'm not sure how
class casting even makes sense - if the object is of one class, how can
you just make it into another class by casting? If you mean "casting"
actually returns another object of different class, then just make a
method for that that returns that object, I do not see how obscuring the
purpose of this operation with unobvious syntax would help.
The discussion is starting to drift very far from my original proposal.
Instead of trying to guess what I mean, can't people just refer to my very
simple definitive proposed behavior?
My proposal is simple: behave as an inline type hint. The same type hints
you have in arguments lists, but inline. The use case is "I want to make
sure this value is of this type" and a side benefit is the IDE can know the
variable is of this type too (for autocompletion purposes).
Whether they'd be exposed with the cast syntax or otherwise isn't that
important. Languages like ActionScript expose inline type validation both by
"static typing" hints and by "casting". In both cases the operation simply
validates the class can be seens as an instance of this class/interface.
Stan
Hi!
My proposal is simple: behave as an inline type hint. The same type hints
you have in arguments lists, but inline. The use case is "I want to make
sure this value is of this type" and a side benefit is the IDE can know the
variable is of this type too (for autocompletion purposes).
What's wrong with instanceof? You can then throw fatal error if you
want, it's just two lines:
if(!($foo instanceof Bar)) {
trigger_error(E_USER_ERROR, "Wrong foo!");
}
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
What's wrong with instanceof? You can then throw fatal error if you
want, it's just two lines:
if(!($foo instanceof Bar)) {
trigger_error(E_USER_ERROR, "Wrong foo!");
}
That's 3 lines on top of the line where you assign the value, and you forgot
the 4th line for the IDE:
/* @var $foo Bar */
$foo = expression();
if(!($foo instanceof Bar)) {
trigger_error(E_USER_ERROR, "Wrong foo!");
}
Versus this:
Bar $foo = expression();
And assignment is a kinda common operation. So I hope you can see what's
wrong with it now.
Stan
Hi!
And assignment is a kinda common operation. So I hope you can see what's
wrong with it now.
No I do not. Not every imaginable use case should have dedicated
language construct for it - sometimes it is OK to type 2 lines of code.
Sometimes even 3. This case is well served by existing language syntax,
which also allows much more flexibility and control over what happens if
the variable does not match. I see no reason to invent language
construct the only purpose of which is to save you typing one if clause.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
And assignment is a kinda common operation. So I hope you can see what's
wrong with it now.No I do not. Not every imaginable use case should have dedicated
language construct for it - sometimes it is OK to type 2 lines of code.
Sometimes even 3. This case is well served by existing language syntax,
which also allows much more flexibility and control over what happens if
the variable does not match. I see no reason to invent language
construct the only purpose of which is to save you typing one if clause.
Let me ask you - do you think the existing PHP typehints are pointless too?
Do you feel they don't give you enough flexibility? Do you feel they
reinvented a language construct for the purpose of saving the typing of one
if clause (per argument) (per method) (per class)?
And why do you keep ignoring the fact that IDE's need additional clutches to
understand the type of the variable?
Stan
Hi!
Let me ask you - do you think the existing PHP typehints are pointless too?
Do you feel they don't give you enough flexibility? Do you feel they
reinvented a language construct for the purpose of saving the typing of one
if clause (per argument) (per method) (per class)?
They are not pointless, but I think they are often misunderstood and not
used correctly. And they definitely lack flexibility in many cases. But
they are helpful for one important thing - defining interface between
the method and the method client. Having strictly typed variables does
not serve it, and trying to make PHP into half-baked
half-statically-typed language does not sound like a good idea to me.
And why do you keep ignoring the fact that IDE's need additional clutches to
understand the type of the variable?
Because I don't think inventing language constructs for the purpose of
helping IDEs simulate static typing in dynamically typed language makes
much sense.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi!
Let me ask you - do you think the existing PHP typehints are pointless
too?
Do you feel they don't give you enough flexibility? Do you feel they
reinvented a language construct for the purpose of saving the typing of
one
if clause (per argument) (per method) (per class)?They are not pointless, but I think they are often misunderstood and not
used correctly. And they definitely lack flexibility in many cases. But
they are helpful for one important thing - defining interface between
the method and the method client. Having strictly typed variables does
not serve it, and trying to make PHP into half-baked
half-statically-typed language does not sound like a good idea to me.
All right, your method accepts an array of objects, instances of Foo. How do
you enforce this contract?
Here's how my proposal enforces it:
function foobar(array $collectionOfFoo) {
foreach ($collectionOfFoo as Foo $item) {
...
}
}
What's your proposal? From the discussion so far, I'd guess it's peppering
out code with if-s with the same error written everywhere everytime we check
the item in an array.
Because I don't think inventing language constructs for the purpose of
helping IDEs simulate static typing in dynamically typed language makes
much sense.
The same applies to typehints, so make up your mind.
Stan
Hi!
All right, your method accepts an array of objects, instances of Foo. How do
you enforce this contract?
You are trying to re-invent generics/parametrized types and bolt it onto
PHP. I still don't think it is a good idea - PHP is not a statically
typed language. Just check you array elements if you need.
What's your proposal? From the discussion so far, I'd guess it's peppering
out code with if-s with the same error written everywhere everytime we check
the item in an array.
By "peppering" here you mean one if. Yes, this is my proposal - if you
need to do a check - do a check.
The same applies to typehints, so make up your mind.
No it does not. But this is exactly why I think one of the problems with
strict typing in arguments is - because people take it and starting to
use it as a legitimation of turning PHP into weird hybrid of dynamically
typed language with random islands of static typing popping in random
places. I still do not think it is a good idea.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi!
All right, your method accepts an array of objects, instances of Foo. How
do
you enforce this contract?You are trying to re-invent generics/parametrized types and bolt it onto
PHP. I still don't think it is a good idea - PHP is not a statically
typed language. Just check you array elements if you need.
You're 10 years too late to argue the merits of typehints in PHP.
I am not proposing the introduction of typehints. I'm just saying "we have
the option to use them in arguments, let's have the options inline too."
This way we can validate expressions and structures we can't today, in a
minimal, readable, consistent, easy to maintain way.
By "peppering" here you mean one if. Yes, this is my proposal - if you
need to do a check - do a check.
Yes, exactly: one if. For your entire codebase that has one single
assignment in it.
Or one foreach. Pick one or the other, but not both, otherwise they become
two ifs, and that invalidated your argument.
The same applies to typehints, so make up your mind.
No it does not. But this is exactly why I think one of the problems with
strict typing in arguments is - because people take it and starting to
use it as a legitimation of turning PHP into weird hybrid of dynamically
typed language with random islands of static typing popping in random
places. I still do not think it is a good idea.
Saying "weird hybrid random islands popping random" doesn't make simple type
validation hints any more awkward than they were yesterday before I posted
this thread, Stas.
Stan
You're 10 years too late to argue the merits of typehints in PHP.
I am not proposing the introduction of typehints. I'm just saying "we have
the option to use them in arguments, let's have the options inline too."
This way we can validate expressions and structures we can't today, in a
minimal, readable, consistent, easy to maintain way.
Stas already pointed out that parameter typehints allow you to define
the interface for your method. Return typehints would server a similar
purpose and as such I'd consider them useful. But "variable" typehints
don't serve any such purpose. Actually, one could even say that they
don't serve any purpose, short of providing the IDE with type
information, because your code would work just as well even without
the type check. If the type were wrong, it would just throw a fatal
error when trying to do something with it (like invoking a method that
does not exist).
And if the sole purpose is type hinting for the IDE, then I don't see
what's wrong with the established system of PHPDoc comments. They seem
to serve the same purpose, don't they?
Nikita
Stas already pointed out that parameter typehints allow you to define
the interface for your method. Return typehints would server a similar
purpose and as such I'd consider them useful. But "variable" typehints
don't serve any such purpose.
I gave an example validating an array of Foo instances, which the current
system doesn't solve. Of course PHP could extend argument typehints to
describe this, but Stas just said he doesn't want generics and so on in
PHP.
All right, I don't either. I just want a clean way to describe my
expectation that a variable is what it is, and assuming that all function
arguments are one single instance simply doesn't match the real world out
there. People iterate arrays, they pass arrays around. And they have
expectations for what's inside those arrays.
Stan
But "variable" typehints
don't serve any such purpose. Actually, one could even say that they
don't serve any purpose, short of providing the IDE with type
information, because your code would work just as well even without
the type check. If the type were wrong, it would just throw a fatal
error when trying to do something with it (like invoking a method that
does not exist).
Just like with argument typehints.
Point me to an argument typehint that is required for your code to run.
You and Stas keep giving arguments against argument typehints, which is
really awkward.
Stan
Just like with argument typehints.
Point me to an argument typehint that is required for your code to run.You and Stas keep giving arguments against argument typehints, which is
really awkward.
As already pointed out repeatedly, argument typehints serve the
purpose of defining an interface. No, they are not required to run the
code, that's true. But they still serve an important purpose for
object oriented programming (and, just to make sure that you don't
miss it again: That purpose is defining the interface). Variable
typehints do not, as far as I can see.
I gave an example validating an array of Foo instances, which the current system doesn't solve.
Yes, and your system doesn't solve it either, or does it? As the
validation does not happen through a parameter typehint it does not
help defining the public interface. It only helps the IDE know the
type (which doc comments can also do).
Nikita
As already pointed out repeatedly, argument typehints serve the
purpose of defining an interface. No, they are not required to run the
code, that's true. But they still serve an important purpose for
object oriented programming (and, just to make sure that you don't
miss it again: That purpose is defining the interface). Variable
typehints do not, as far as I can see.
I was most of the way through writing a much longer e-mail responding
to the original post, but you and Stas have summed it up well, really.
Type hints actually have a use in the object model of PHP in terms of
interface definition. The only uses I can see for these variable hints
are:
-
An informative use for IDEs, as previously noted, which is already
filled adequately by @var documentation. -
An assertive use in development: effectively, a different way of
writing assert($var instanceof ClassName) to verify your assumptions
on variable types.
Personally, I don't think either of those justify the addition of the feature.
The thing is that even ignoring type hints' interface definition
functionality and treating them as pure syntactic sugar, type hints
have another benefit: if you have several parameters to a function,
type hints allow you to verify their classes in one hit, rather than
having to make several calls to a verification function or implement
something like zpp for objects in userspace. That leads to neater,
shorter code. This feature doesn't have that quality: you can only
hint one variable at a time, so there's not even a significant saving
in time/typing for the developer between (to pick the only version of
the syntax I don't find completely objectionable) "ClassName $var =
$object;" and "$var = isType($object, 'ClassName');".
In summary, I guess I'm -1 on the feature, and -10⁹ on any version of
the feature that looks like a typecast. :)
Adam
2012/8/15 Stan Vass sv_forums@fmethod.com
But "variable" typehints
don't serve any such purpose. Actually, one could even say that they
don't serve any purpose, short of providing the IDE with type
information, because your code would work just as well even without
the type check. If the type were wrong, it would just throw a fatal
error when trying to do something with it (like invoking a method that
does not exist).Just like with argument typehints.
Point me to an argument typehint that is required for your code to run.
Hi,
Point me to an argument inerfaces are required. Or boolean (would could use
0/1 instead). Or abstract methods. Or function/methods parameters (we could
use func_get_args()
). Or default parameters. Or [insert random feature
here].
Or: Point me to an argument, why the array of "Foo" shouldn't be a
specialised class, that implements 'Iteratable'. With this your foreach
"problem" simply disappear and everything, what remains, is something to
make IDEs happy (with one line less to write...).
My opinion
Regards,
Sebastian
You and Stas keep giving arguments against argument typehints, which is
really awkward.
Stan
Stan,
Hi!
I agree with you. The one case where this syntax may be very useful is if
we want to implement class casting. So introduce a pair of magic methods
I do not think we want to implement class casting. I'm not sure how
class casting even makes sense - if the object is of one class, how can
you just make it into another class by casting? If you mean "casting"
actually returns another object of different class, then just make a
method for that that returns that object, I do not see how obscuring the
purpose of this operation with unobvious syntax would help.The discussion is starting to drift very far from my original proposal.
Instead of trying to guess what I mean, can't people just refer to my very
simple definitive proposed behavior?
My point was that what I posted was the only way that I can see for the
original proposal to be useful.
Anthony
On Wed, Aug 15, 2012 at 4:48 AM, Anthony Ferrara ircmaxell@gmail.comwrote:
Stan,
Hi!
I agree with you. The one case where this syntax may be very useful is
ifwe want to implement class casting. So introduce a pair of magic
methodsI do not think we want to implement class casting. I'm not sure how
class casting even makes sense - if the object is of one class, how can
you just make it into another class by casting? If you mean "casting"
actually returns another object of different class, then just make a
method for that that returns that object, I do not see how obscuring the
purpose of this operation with unobvious syntax would help.The discussion is starting to drift very far from my original proposal.
Instead of trying to guess what I mean, can't people just refer to my
very
simple definitive proposed behavior?My point was that what I posted was the only way that I can see for the
original proposal to be useful.Anthony
Though I'm clearly in the minority on this, I for one think this proposal
does have more merit than is being argued. There seems to be general
agreement all around that this would provide a benefit as it pertains to
code readability-- Not just by humans, but theoretically by doc/etc parsers
as well.
This is where we get into arbitrary, subjective territory. To me, that
benefit in and of itself is sufficient to warrant this feature. To many of
you, it is not enough.
The tie-breaker for me is the fact that, though the benefits are modest,
there's really no noticeable cost, either. The argument seems to,
essentially, break down as follows: "This feature isn't worth our time."
.... "Yes, it is!" .... "No, it isn't."
There is clearly demand for this feature, even though its usefulness would
be modest. Since it really wouldn't harm the language to just add it (if
done correctly of course), my thinking is that we should just go ahead and
add it. If nothing else, one benefit that hasn't been mentioned is the
reduced traffic on Internals due to people no longer asking for it. ;)
Just my three-and-a-half cents (damn inflation!).
--Kris
On Wed, Aug 15, 2012 at 4:48 AM, Anthony Ferrara ircmaxell@gmail.comwrote:
Stan,
Hi!
I agree with you. The one case where this syntax may be very useful is
ifwe want to implement class casting. So introduce a pair of magic
methodsI do not think we want to implement class casting. I'm not sure how
class casting even makes sense - if the object is of one class, how can
you just make it into another class by casting? If you mean "casting"
actually returns another object of different class, then just make a
method for that that returns that object, I do not see how obscuring the
purpose of this operation with unobvious syntax would help.The discussion is starting to drift very far from my original proposal.
Instead of trying to guess what I mean, can't people just refer to my
very
simple definitive proposed behavior?My point was that what I posted was the only way that I can see for the
original proposal to be useful.Anthony
Though I'm clearly in the minority on this, I for one think this proposal
does have more merit than is being argued. There seems to be general
agreement all around that this would provide a benefit as it pertains to
code readability-- Not just by humans, but theoretically by doc/etc parsers
as well.This is where we get into arbitrary, subjective territory. To me, that
benefit in and of itself is sufficient to warrant this feature. To many of
you, it is not enough.The tie-breaker for me is the fact that, though the benefits are modest,
there's really no noticeable cost, either. The argument seems to,
essentially, break down as follows: "This feature isn't worth our time."
.... "Yes, it is!" .... "No, it isn't."
Every feature has a cost, even if that cost is just maintaining the
code. Doing language changes for minority use cases, which already
have sensible solutions, doesn't make much sense.
Another aspect here is that there is no reasonable syntax for this
feature, at least I can't think of one:
- The syntax
$foo = (InterfaceName) $container->service
is
completely out of question. It looks like a cast, but wouldn't
actually do a cast. - Same is to be said about
InterfaceName $foo = $container->service
. This syntax implies that the $foo variable will
always be of type InterfaceName, even if it is later reassigned. It's
not a sensible syntax for a one time validation - The other three syntaxes that were mentioned were just as unclear.
E.g.$foo = $container->service as InterfaceName
again looks like a
strange cast syntax and$foo = $container->service is InterfaceName
looks like the assignment should evaluate to a boolean (i.e.is
is
some kind ofinstanceof
).
On the other hand, the current ways of accomplishing the same goal are
well-established and easy to understand:
- Using a docblock: /** @var $foo IntefaceName **/
- Using an assertion: assert($foo instanceof InterfaceName).
I think that the assertion is a rather concise and clear way to do
this. It is much more obvious than some new and obscure $foo = (InterfaceName $container->service)
syntax.
Nikita
Hi,
after reading this mail: Is it just me or is a userspace implementation
really that trivial?
function ensure($object, $class) {
if ($object instanceof $class) {
return $object;
}
throw new InvalidArgumentException(sprintf('Object is not of type %s',
$class));
}
And then instead of all a new syntax
$myObject = ensure($another->foobar, MyType::class); // [1]
Did I miss something.
Regards,
Sebastian
[1] There was another RFC that suggested this special property.
2012/8/15 Nikita Popov nikita.ppv@gmail.com
On Wed, Aug 15, 2012 at 4:48 AM, Anthony Ferrara <ircmaxell@gmail.com
wrote:Stan,
On Wed, Aug 15, 2012 at 3:57 AM, Stan Vass sv_forums@fmethod.com
wrote:Hi!
I agree with you. The one case where this syntax may be very useful
is
ifwe want to implement class casting. So introduce a pair of magic
methodsI do not think we want to implement class casting. I'm not sure how
class casting even makes sense - if the object is of one class, how
can
you just make it into another class by casting? If you mean "casting"
actually returns another object of different class, then just make a
method for that that returns that object, I do not see how obscuring
the
purpose of this operation with unobvious syntax would help.The discussion is starting to drift very far from my original
proposal.Instead of trying to guess what I mean, can't people just refer to my
very
simple definitive proposed behavior?My point was that what I posted was the only way that I can see for the
original proposal to be useful.Anthony
Though I'm clearly in the minority on this, I for one think this proposal
does have more merit than is being argued. There seems to be general
agreement all around that this would provide a benefit as it pertains to
code readability-- Not just by humans, but theoretically by doc/etc
parsers
as well.This is where we get into arbitrary, subjective territory. To me, that
benefit in and of itself is sufficient to warrant this feature. To many
of
you, it is not enough.The tie-breaker for me is the fact that, though the benefits are modest,
there's really no noticeable cost, either. The argument seems to,
essentially, break down as follows: "This feature isn't worth our time."
.... "Yes, it is!" .... "No, it isn't."Every feature has a cost, even if that cost is just maintaining the
code. Doing language changes for minority use cases, which already
have sensible solutions, doesn't make much sense.Another aspect here is that there is no reasonable syntax for this
feature, at least I can't think of one:
- The syntax
$foo = (InterfaceName) $container->service
is
completely out of question. It looks like a cast, but wouldn't
actually do a cast.- Same is to be said about
InterfaceName $foo = $container->service
. This syntax implies that the $foo variable will
always be of type InterfaceName, even if it is later reassigned. It's
not a sensible syntax for a one time validation- The other three syntaxes that were mentioned were just as unclear.
E.g.$foo = $container->service as InterfaceName
again looks like a
strange cast syntax and$foo = $container->service is InterfaceName
looks like the assignment should evaluate to a boolean (i.e.is
is
some kind ofinstanceof
).On the other hand, the current ways of accomplishing the same goal are
well-established and easy to understand:
- Using a docblock: /** @var $foo IntefaceName **/
- Using an assertion: assert($foo instanceof InterfaceName).
I think that the assertion is a rather concise and clear way to do
this. It is much more obvious than some new and obscure$foo = (InterfaceName $container->service)
syntax.Nikita
On Wed, Aug 15, 2012 at 4:48 AM, Anthony Ferrara <ircmaxell@gmail.commailto:ircmaxell@gmail.com>wrote:
Stan,
Hi!
I agree with you. The one case where this syntax may be very useful is
if
we want to implement class casting. So introduce a pair of magic
methods
I do not think we want to implement class casting. I'm not sure how
class casting even makes sense - if the object is of one class, how can
you just make it into another class by casting? If you mean "casting"
actually returns another object of different class, then just make a
method for that that returns that object, I do not see how obscuring the
purpose of this operation with unobvious syntax would help.
The discussion is starting to drift very far from my original proposal.
Instead of trying to guess what I mean, can't people just refer to my
very
simple definitive proposed behavior?
My point was that what I posted was the only way that I can see for the
original proposal to be useful.
Anthony
Though I'm clearly in the minority on this, I for one think this proposal
does have more merit than is being argued. There seems to be general
agreement all around that this would provide a benefit as it pertains to
code readability-- Not just by humans, but theoretically by doc/etc parsers
as well.
This is where we get into arbitrary, subjective territory. To me, that
benefit in and of itself is sufficient to warrant this feature. To many of
you, it is not enough.
The tie-breaker for me is the fact that, though the benefits are modest,
there's really no noticeable cost, either. The argument seems to,
essentially, break down as follows: "This feature isn't worth our time."
.... "Yes, it is!" .... "No, it isn't."
Every feature has a cost, even if that cost is just maintaining the
code. Doing language changes for minority use cases, which already
have sensible solutions, doesn't make much sense.
Another aspect here is that there is no reasonable syntax for this
feature, at least I can't think of one:
- The syntax
$foo = (InterfaceName) $container->service
is
completely out of question. It looks like a cast, but wouldn't
actually do a cast. - Same is to be said about
InterfaceName $foo = $container->service
. This syntax implies that the $foo variable will
always be of type InterfaceName, even if it is later reassigned. It's
not a sensible syntax for a one time validation - The other three syntaxes that were mentioned were just as unclear.
E.g.$foo = $container->service as InterfaceName
again looks like a
strange cast syntax and$foo = $container->service is InterfaceName
looks like the assignment should evaluate to a boolean (i.e.is
is
some kind ofinstanceof
).
good points
On the other hand, the current ways of accomplishing the same goal are
well-established and easy to understand:
- Using a docblock: /** @var $foo IntefaceName **/
- Using an assertion: assert($foo instanceof InterfaceName).
I think that the assertion is a rather concise and clear way to do
this. It is much more obvious than some new and obscure $foo = (InterfaceName $container->service)
syntax.
@Stan: If you make sure you configure your container to injection dependencies and in case of lazy loading inject factories with type hinting in doc istead of passing the [dependency injection] container around as a registry, then you almost don't get this problem at all, and you will avoid introducing container awareness/dependency in your architecture.
Only place you will have this original problem though is in the code that gets the first dependency of the execution, but even then you can have Container interface for the most common root dependencies. Like: https://github.com/ezsystems/ezp-next/blob/master/eZ/Publish/API/Container.php
Nikita
( resending with correct formatting, and missing context while at it, sorry about that )
(...)
Another aspect here is that there is no reasonable syntax for this
feature, at least I can't think of one:
- The syntax
$foo = (InterfaceName) $container->service
is
completely out of question. It looks like a cast, but wouldn't
actually do a cast.- Same is to be said about
InterfaceName $foo = $container->service
. This syntax implies that the $foo variable will
always be of type InterfaceName, even if it is later reassigned. It's
not a sensible syntax for a one time validation- The other three syntaxes that were mentioned were just as unclear.
E.g.$foo = $container->service as InterfaceName
again looks like a
strange cast syntax and$foo = $container->service is InterfaceName
looks like the assignment should evaluate to a boolean (i.e.is
is
some kind ofinstanceof
).
good points
In addition, the root cause that triggered this proposal in the first place: serve container / object registry doc issue, is kind of moot, ref bellow.
On the other hand, the current ways of accomplishing the same goal are
well-established and easy to understand:
- Using a docblock: /** @var $foo IntefaceName **/
- Using an assertion: assert($foo instanceof InterfaceName).
I think that the assertion is a rather concise and clear way to do
this. It is much more obvious than some new and obscure$foo = (InterfaceName $container->service)
syntax.
To expand on that, @Stan: If you make sure you configure your container to injection dependencies (and in case of lazy loading, inject factories* with type hinting in doc) instead of passing the [dependency injection] container around as a registry, then you almost don't get this problem at all, and you will avoid introducing container awareness/dependency in your architecture.
Only place you will have this original problem though is in the code that gets the first dependency of the execution, like in index.php for instance, but even then you can have Container interface for the most common root dependencies.
In the cases that doesn't fit, you should plainly use the doc block referred to by Nikita, it is already supported by IDE's and won't need additional 3 years to get support.
- As alternatives to factories with or without container knowledge, there is one alternative that some containers support:
Proxy objects: container generates proxy objects whenever you want dependencies to be lazy loaded, they have container awareness, but this becomes 100% transparent to your code, but it probably adds some overhead.
I'd like to also ask people to read what the intended effect of the proposal
is instead of going into abstract discussions about how casting one class to
another doesn't make sense (this is not what's being proposed).
Just like PHP typehints look like static typing but aren't, the same way
the fact this looks like a static cast doesn't make it so. A dynamic
language can't have static casts, and I'd think this is obvious to
everybody.
Instead, I'm adapting the principle so it fits with existing PHP behaviors
and patterns.
Syntax which looks like static typing is fine by me as well. Examples:
ClassName $foo = expression();
foreach ($list as InterfaceName $item) { ... }
etc.
The only operation done here is validating the variable is a valid instance
of this type. No transformation is happening.
Stan
I'd like to also ask people to read what the intended effect of the proposal
is instead of going into abstract discussions about how casting one class to
another doesn't make sense (this is not what's being proposed).
I think you confused everyone by a) having "typecasting" in the title
and b) starting with the (Foo) casting syntax (so everyone assumed
that you indeed want some kind of class casts, whatever that may be).
Regarding the actual proposal, could you maybe clarify the use-cases
for this? I can see that it could be useful in principle, but your
actually named use cases confuse me somewhat. In particular, I don't
see how this would help dependency injection containers. I can see
that it helps service locators and registries, but both of those are
considered antipatterns, so there is no reason to add additional
language features for them. DICs are only used to inject top-level
dependencies, so in that case types should be fairly well covered by
parameter type hints.
Nikita
I'd like to also ask people to read what the intended effect of the
proposal
is instead of going into abstract discussions about how casting one class
to
another doesn't make sense (this is not what's being proposed).I think you confused everyone by a) having "typecasting" in the title
and b) starting with the (Foo) casting syntax (so everyone assumed
that you indeed want some kind of class casts, whatever that may be).
I had "typecasting / typehinting" in the title, and I'd like to remind
everyone again that in dynamically typed languages class casts are often
implemented as a basic validation operation, consistent with what I
proposed.
Regarding the actual proposal, could you maybe clarify the use-cases
for this? I can see that it could be useful in principle, but your
actually named use cases confuse me somewhat. In particular, I don't
see how this would help dependency injection containers. I can see
that it helps service locators and registries, but both of those are
considered antipatterns, so there is no reason to add additional
language features for them. DICs are only used to inject top-level
dependencies, so in that case types should be fairly well covered by
parameter type hints.
Two use cases apart from registries: PHP has no typed iteration and arrays,
so you the only way to guarantee (and the IDE to know) the type of a
variable in these cases is a hint:
Foo $bar = $array[1];
foreach ($array as Foo $item) { ... }
Automatically this applies to everything that uses ArrayAccess as a
shorthand too, and properties of anonymous objects (stdClass).
The current alternative is peppering code with pseudo-PHPDoc inline hints,
and instanceof assertions which truly is a facility the language core should
provide, instead of us emulating it.
Stan