Good morning, internals!
I would like to present to you an idea that I have for a syntax improvement
for PHP.
The basic idea is to allow arbitrary expressions when using the instanceof
operator. Currently, the second operand can only be a constant reference or
a string:
$foo instanceof stdClass;
What I want to implement is the ability to allow arbitrary expressions on
the second operand, so instead of having to write something like this:
$className = 'stdClass';
$foo instanceof $className;
We could write something like this:
$foo instanceof ($bar->getClassName());
I've been working with Nikita Nefedov on this improvement, and we managed
to reach a very simple way to implement it, and it looks pretty good so far.
Currently, I don't have a VCS account, and eventually I want to open a
formal RFC for this, but I first wanted to discuss this with you guys to
see the impressions on it and suggestions as well.
Regarding BC breaks, there would be none from what I can see so far -
hopefully someone more experienced will be able to point my any.
So, what do you think?
Cheers!
Daniel Ribeiro
http://danielribeiro.org
Oh, and thanks to @SaraMG for pointing me to the write direction on writing
an e-mail to the internals :)
Daniel Ribeiro
http://danielribeiro.org
Good morning, internals!
I would like to present to you an idea that I have for a syntax
improvement for PHP.The basic idea is to allow arbitrary expressions when using the instanceof
operator. Currently, the second operand can only be a constant reference or
a string:$foo instanceof stdClass;
What I want to implement is the ability to allow arbitrary expressions on
the second operand, so instead of having to write something like this:$className = 'stdClass';
$foo instanceof $className;We could write something like this:
$foo instanceof ($bar->getClassName());
I've been working with Nikita Nefedov on this improvement, and we managed
to reach a very simple way to implement it, and it looks pretty good so far.Currently, I don't have a VCS account, and eventually I want to open a
formal RFC for this, but I first wanted to discuss this with you guys to
see the impressions on it and suggestions as well.Regarding BC breaks, there would be none from what I can see so far -
hopefully someone more experienced will be able to point my any.So, what do you think?
Cheers!
Daniel Ribeiro
http://danielribeiro.org
Hi!
What I want to implement is the ability to allow arbitrary expressions on
the second operand, so instead of having to write something like this:
I'm afraid there's a problem with this. Arbitrary expressions include
constants, right? So what this means:
var_dump($foo instanceof Bar);
is it checking $foo for being instance of class Bar (that's what is
happening now) or is it taking the value of the constant Bar (whatever
it is) - since constant is an expression - and using it as a class name
and then checking if $foo is an instance of that class?
You could of course require the expression to always be enclosed in (),
but that produces weird syntax where some forms of instanceof work
without () and some only with (). Given that you can easily assign your
value to a variable, is it worth it?
Also, you can always use is_a($foo, $bar->getClassName()).
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
On Thu, 06 Nov 2014 13:01:52 +0400, Stas Malyshev smalyshev@sugarcrm.com
wrote:
Hi!
What I want to implement is the ability to allow arbitrary expressions
on
the second operand, so instead of having to write something like this:I'm afraid there's a problem with this. Arbitrary expressions include
constants, right? So what this means:var_dump($foo instanceof Bar);
is it checking $foo for being instance of class Bar (that's what is
happening now) or is it taking the value of the constant Bar (whatever
it is) - since constant is an expression - and using it as a class name
and then checking if $foo is an instance of that class?You could of course require the expression to always be enclosed in (),
but that produces weird syntax where some forms of instanceof work
without () and some only with (). Given that you can easily assign your
value to a variable, is it worth it?Also, you can always use is_a($foo, $bar->getClassName()).
Hey Stas,
You're right about parenthesis - they are required to use expressions.
Basically when you're in parenthesis - it will only mean that it's an
expression, otherwise it's a direct class reference. It could be worked
around by creating a new class of expression (on parser level, say
expr_not_single_const or anyting like that) that would match any
expression except constant references, but that's too much I guess.
Also one thing not mentioned in the initial letter - this will also allow
you to use expressions for new operator in the same way: new (str_replace('/', '\\', $classPath))()
- just an example.
I would say that it's just not logical to have some operator that can
accept dynamic (runtime-defined) value but not an expression.
Hi!
Also one thing not mentioned in the initial letter - this will also allow
you to use expressions for new operator in the same way:new (str_replace('/', '\\', $classPath))()
- just an example.
OK, if we apply it consistently - i.e. say anywhere that we allow
literal or ${variable-like expression} we also allow (generic
expression) - then it would probably work. I'm still not sure I like it
too much - for instance, if I saw something like the example above in
the code review, I'd ask to rewrite it with a variable, since it's
unreadable and all too easy to make a mistake. Variables are not that
bad, and not everything needs to be a one-liner.
I would say that it's just not logical to have some operator that can
accept dynamic (runtime-defined) value but not an expression.
Right now, many constructs do exactly that - they accept literal or
variable (with some stretching of what "variable" is, esp. with uniform
syntax RFC which allows to stuff quite a lot in a variable) but not
generic expression. However, the same uniform variable RFC allows many
operations now to accept expressions via (expression) syntax, so maybe
we can expand on that further and allow this in any context where
literal+variable previously were accepted. I.e. now FOO() accepts FOO
being (expression) but new FOO() does not, which does seem a bit
inconsistent. So maybe it can be done. I'm still not sure personally
doing this is a good thing - it is too easy to make code completely
incomprehensible with this - but maybe I'm wrong here.
I think it may be worth asking Nikita Popov if if it's be feasible to
extend his RFC to these cases.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
On Thu, Nov 6, 2014 at 1:01 PM, Stas Malyshev smalyshev@sugarcrm.com
wrote:
You could of course require the expression to always be enclosed in (),
but that produces weird syntax where some forms of instanceof work
without () and some only with (). Given that you can easily assign your
value to a variable, is it worth it?Also, you can always use is_a($foo, $bar->getClassName()).
This is exactly what I'm doing right now, requiring the expression to
always be enclosed in parenthesis. I think it's way better to be able to do
this instead of creating temporary variables just to assign a class name.
Also, is_a, since it's a function, is significantly slower than instanceof,
which is a construct (but of course you already now that).
Daniel Ribeiro
http://danielribeiro.org
On Thu, Nov 6, 2014 at 1:01 PM, Stas Malyshev smalyshev@sugarcrm.com
wrote:You could of course require the expression to always be enclosed in (),
but that produces weird syntax where some forms of instanceof work
without () and some only with (). Given that you can easily assign your
value to a variable, is it worth it?Also, you can always use is_a($foo, $bar->getClassName()).
This is exactly what I'm doing right now, requiring the expression to
always be enclosed in parenthesis. I think it's way better to be able to do
this instead of creating temporary variables just to assign a class name.
Also, is_a, since it's a function, is significantly slower than instanceof,
which is a construct (but of course you already now that).
This is still pretty weird, $foo instanceof Bar and $foo instanceof (Bar) shouldn’t be different.
Perhaps, dare I say it, we should merge the constant and class namespaces in PHP7? Those are perhaps the least likely to conflict. It’d mean we could handle instanceof expressions, and we wouldn’t need to use ::class.
--
Andrea Faulds
http://ajf.me/
Perhaps, dare I say it, we should merge the constant and class namespaces
in PHP7? Those are perhaps the least likely to conflict. It’d mean we could
handle instanceof expressions, and we wouldn’t need to use ::class.
Hi Andrea!
I'm not sure I understand what you mean by "don't need to use ::class".
Currently, we can only use the class constant itself, like $foo instanceof
stdClass or a string representation of that class' name.
Concerning the parenthesis, I agree they shouldn't be treated differently,
but as for now they are.
Daniel Ribeiro
http://danielribeiro.org
Perhaps, dare I say it, we should merge the constant and class namespaces
in PHP7? Those are perhaps the least likely to conflict. It’d mean we could
handle instanceof expressions, and we wouldn’t need to use ::class.Hi Andrea!
I'm not sure I understand what you mean by "don't need to use ::class”.
By merging the symbol tables, you could reference classes like constants (perhaps it’d return some sort of ReflectionClass-like thing?):
$x = SomeClass;
$foo = new $x;
Currently, because SomeClass above would resolve to a constant, you have to use the weird pseudo-constant ::class:
$x = SomeClass::class;
It also would mean instanceof could accept arbitrary expressions, as there’d be no syntactic ambiguity:
class Foo {}
const Bar = ‘Foo';
$x = (new Foo) instanceof Bar; // works (Bar resolves to ‘Foo’, valid class name)
$x = (new Foo) instanceof Foo; // works (Foo is a class)
const Foo; // Not allowed, conflicts with class
--
Andrea Faulds
http://ajf.me/
By merging the symbol tables, you could reference classes like constants
(perhaps it’d return some sort of ReflectionClass-like thing?):$x = SomeClass; $foo = new $x;
Currently, because SomeClass above would resolve to a constant, you have
to use the weird pseudo-constant ::class:$x = SomeClass::class;
It also would mean instanceof could accept arbitrary expressions, as
there’d be no syntactic ambiguity:class Foo {} const Bar = ‘Foo'; $x = (new Foo) instanceof Bar; // works (Bar resolves to ‘Foo’, valid
class name)
$x = (new Foo) instanceof Foo; // works (Foo is a class)
const Foo; // Not allowed, conflicts with class
Yeah, that makes perfect sense.
Also, I just realized that HHVM accepts expressions wrapped in parenthesis.
I might need to take a look at how it's done there.
Daniel Ribeiro
http://danielribeiro.org
Hi!
This is exactly what I'm doing right now, requiring the expression to
always be enclosed in parenthesis. I think it's way better to be able to
do this instead of creating temporary variables just to assign a class
Why? What's so bad in variables? It doesn't cost that much and makes you
code clearer.
name. Also, is_a, since it's a function, is significantly slower than
instanceof, which is a construct (but of course you already now that).
I find it very hard to accept this particular argument. First, if your
code significantly depends on the speed of instanceof, you probably have
some very uncommon code that does some very uncommon things. For such
code, changing syntax of PHP may be not the best idea. Secondly, if we
discover that the speed of is_a is a common problem, we can treat it -
i.e. by converting it to opcode, etc. - but in general the argument
"function calls are too slow in PHP so we should have duplicates for
them" sounds wrong. They are not that slow and in most cases it's
completely fine to use functions. If your particular code is so
performance-sensitive that the speed of instanceof really matters so
much that function call is not acceptable, maybe it's time for a little
C extension?
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
On Fri, Nov 7, 2014 at 3:50 AM, Stas Malyshev smalyshev@sugarcrm.com
wrote:
I find it very hard to accept this particular argument.
Honestly, I find it hard it too. The reason I started this is that I tried
to do something like $foo instanceof $bar->getClassName() and
I got a syntax error. It looks very straightforward and it should be the
expected behavior, except that it doesn't work. So this is the main
reason I started thinking about this: it's an improvement that aims
readability and easiness. Now, I'm sure you can agree with me that it's
way better than having a variable holding the class name.
Daniel Ribeiro
http://danielribeiro.org