[RFC] Variable syntax tweaks

php.internals

Nikita Popov

6 years ago
Hi internals, I'd like to propose a small RFC, which addresses a few minor issues that have not been handled by the original "uniform variable syntax" RFC: https://wiki.php.net/rfc/variable_syntax_tweaks This is all about edge cases of edge cases, of course. I think the only part here that is not entirely straightforward and may need some discussion is how arbitrary expression support for instanceof should be handled. Regards, Nikita

Rowan Collins

6 years ago
On Tue, 7 Jan 2020 at 10:23, Nikita Popov <nikita.ppv@gmail.com> wrote:
> I'd like to propose a small RFC, which addresses a few minor issues that > have not been handled by the original "uniform variable syntax" RFC: > > https://wiki.php.net/rfc/variable_syntax_tweaks
Hi Nikita, Thanks for this, I'm definitely a fan of this kind of consistency, even if it rarely matters in practice. :) Regarding instanceof, and specifically your last alternative:
> The second possibility is to relax the restrictions around the
right-hand-side of instanceof entirely. This would involve treating it as a normal expression, and then reinterpreting plain constant accesses as class name references instead. Am I right in thinking that another disadvantage of this is that you couldn't use a bare constant to define a class name, thus introducing a new inconsistency? That is, using a bracketed form, it should be possible to write: const CLASS_NAME='MyClass'; var_dump( $string instanceof {CLASS_NAME} ); or: const CLASS_NAME='MyClass'; var_dump( $string instanceof (CLASS_NAME) ); but using the "reinterpreted expression" option, you'd need to do something hacky to force the interpretation as a constant, like: const CLASS_NAME='MyClass'; var_dump( $string instanceof ('' . CLASS_NAME) ); Another edge case of an edge case, of course, but a mark against that option in my view. :) Regards,
-- Rowan Tommins [IMSoP]

Nikita Popov

6 years ago
On Tue, Jan 7, 2020 at 11:43 AM Rowan Tommins <rowan.collins@gmail.com> wrote:
> On Tue, 7 Jan 2020 at 10:23, Nikita Popov <nikita.ppv@gmail.com> wrote: > > > I'd like to propose a small RFC, which addresses a few minor issues that > > have not been handled by the original "uniform variable syntax" RFC: > > > > https://wiki.php.net/rfc/variable_syntax_tweaks > > > > > Hi Nikita, > > Thanks for this, I'm definitely a fan of this kind of consistency, even if > it rarely matters in practice. :) > > Regarding instanceof, and specifically your last alternative: > > > The second possibility is to relax the restrictions around the > right-hand-side of instanceof entirely. This would involve treating it as a > normal expression, and then reinterpreting plain constant accesses as class > name references instead. > > Am I right in thinking that another disadvantage of this is that you > couldn't use a bare constant to define a class name, thus introducing a new > inconsistency? That is, using a bracketed form, it should be possible to > write: > > const CLASS_NAME='MyClass'; > var_dump( $string instanceof {CLASS_NAME} ); > > or: > > const CLASS_NAME='MyClass'; > var_dump( $string instanceof (CLASS_NAME) ); > > but using the "reinterpreted expression" option, you'd need to do something > hacky to force the interpretation as a constant, like: > > const CLASS_NAME='MyClass'; > var_dump( $string instanceof ('' . CLASS_NAME) ); >
If we went with this option, we'd only interpret a plain "constant" access as a class name reference. "instanceof (FOO)" should definitely be interpreted as a constant access, not a class reference. Nikita

Claude Pache

6 years ago
> Le 7 janv. 2020 à 11:23, Nikita Popov <nikita.ppv@gmail.com> a écrit : > > Hi internals, > > I'd like to propose a small RFC, which addresses a few minor issues that > have not been handled by the original "uniform variable syntax" RFC: > > https://wiki.php.net/rfc/variable_syntax_tweaks > > This is all about edge cases of edge cases, of course. I think the only > part here that is not entirely straightforward and may need some discussion > is how arbitrary expression support for instanceof should be handled. > > Regards, > Nikita
Hi, The RFC looks good for me, except for one point. Concerning the arbitrary expression support for `new` and `instanceof`, I strongly think that the most consistant choice for delimiters among “(...)” (parentheses) and “{...}” (braces) is not braces “{...}”, but parentheses “(...)”. Your argument is based on the position of the expression (RHS vs LHS). My argument is based on the type (in a broad sense) of the thing that the expression is supposed to represent. The braces are used when the expression is expected to represent: * a variable name: `${...}` * a property name: `$x->{...}` — `X::${...}` * a method name: `$x->{...}()` — `X::{...}()` In all those cases, the expression inside `{...}` must evaluate to a string, and will be interpreted as a name. On the other hand, the parentheses are used when the expression is expected to represent: * an array: `(...)["key"]` * an object: `(...)->prop` — `(....)->meth()` — `clone (...)` * a function: `(...)($arg)` * a class: `(...)::KONST` — `(...)::${statProp}` — `(...)::${statMeth}()` In the first two cases, the expected entity, “array” or “object”, is a first-class value, and the expression inside `(...)` will be interpreted as such. The last two cases are more interesting. For the ”function” cases, it can be: * a string representing a function (interpreted as the fully qualified name of a function); * an array `[ $obj, "meth" ]`, `[ "klass", "meth" ]` or a string "klass::meth" representing a method; * a closure or another object implementing the magic __invoke() method. For the “class” case, it can be: * a string representing a class (interpreted as the fully qualified name of a class); * an instance of a class. In those cases, the expected entity may be a first-class citizen (a closure, an instance of a class), or an entity that, although not a first-class citizen, is unambiguously(*) represented by some other first-class value (a function by their fully qualified name, etc.) and could have been reasonably designed as first-class citizen (and indeed, a function may be replaced with a Closure object with the same functionality). (*) (For the sake of not complicating the argument, I’m ignoring callables whose meaning depends on context such as `["self", "foo"]`.) You rightly noted that the braces `{...}` are used exclusively on the RHS; that follows from their meaning: a bare name has no significance out of context, where the context is whether it is a function name, or whether it is a property/method name and of which object/class the property/method is, or etc. That context is more naturally provided before (at the left of) the name. On the other hand the parentheses `(...)` are often used on the LHS: this place is the natural place for an entity (an object, a class, etc.) that don’t need more context to be well-defined, and that serves as target for some action (call the function, look up the property of an object, etc.) However, although the entity is often placed at LHS, this is not systematic; consider f.e. `clone $obj`, which is quite similar to `new klass`. —Claude

Nikita Popov

6 years ago
On Thu, Jan 16, 2020 at 10:12 AM Claude Pache <claude.pache@gmail.com> wrote:
> > > > Le 7 janv. 2020 à 11:23, Nikita Popov <nikita.ppv@gmail.com> a écrit : > > > > Hi internals, > > > > I'd like to propose a small RFC, which addresses a few minor issues that > > have not been handled by the original "uniform variable syntax" RFC: > > > > https://wiki.php.net/rfc/variable_syntax_tweaks > > > > This is all about edge cases of edge cases, of course. I think the only > > part here that is not entirely straightforward and may need some > discussion > > is how arbitrary expression support for instanceof should be handled. > > > > Regards, > > Nikita > > Hi, > > The RFC looks good for me, except for one point. Concerning the arbitrary > expression support for `new` and `instanceof`, I strongly think that the > most consistant choice for delimiters among “(...)” (parentheses) and > “{...}” (braces) is not braces “{...}”, but parentheses “(...)”. Your > argument is based on the position of the expression (RHS vs LHS). My > argument is based on the type (in a broad sense) of the thing that the > expression is supposed to represent. > > The braces are used when the expression is expected to represent: > > * a variable name: `${...}` > * a property name: `$x->{...}` — `X::${...}` > * a method name: `$x->{...}()` — `X::{...}()` > > In all those cases, the expression inside `{...}` must evaluate to a > string, and will be interpreted as a name. > > On the other hand, the parentheses are used when the expression is > expected to represent: > > * an array: `(...)["key"]` > * an object: `(...)->prop` — `(....)->meth()` — `clone (...)` > * a function: `(...)($arg)` > * a class: `(...)::KONST` — `(...)::${statProp}` — `(...)::${statMeth}()` > > In the first two cases, the expected entity, “array” or “object”, is a > first-class value, and the expression inside `(...)` will be interpreted as > such. > > The last two cases are more interesting. For the ”function” cases, it can > be: > * a string representing a function (interpreted as the fully qualified > name of a function); > * an array `[ $obj, "meth" ]`, `[ "klass", "meth" ]` or a string > "klass::meth" representing a method; > * a closure or another object implementing the magic __invoke() method. > > For the “class” case, it can be: > * a string representing a class (interpreted as the fully qualified name > of a class); > * an instance of a class. > > In those cases, the expected entity may be a first-class citizen (a > closure, an instance of a class), or an entity that, although not a > first-class citizen, is unambiguously(*) represented by some other > first-class value (a function by their fully qualified name, etc.) and > could have been reasonably designed as first-class citizen (and indeed, a > function may be replaced with a Closure object with the same functionality). > > (*) (For the sake of not complicating the argument, I’m ignoring callables > whose meaning depends on context such as `["self", "foo"]`.) > > You rightly noted that the braces `{...}` are used exclusively on the RHS; > that follows from their meaning: a bare name has no significance out of > context, where the context is whether it is a function name, or whether it > is a property/method name and of which object/class the property/method is, > or etc. That context is more naturally provided before (at the left of) the > name. > > On the other hand the parentheses `(...)` are often used on the LHS: this > place is the natural place for an entity (an object, a class, etc.) that > don’t need more context to be well-defined, and that serves as target for > some action (call the function, look up the property of an object, etc.) > However, although the entity is often placed at LHS, this is not > systematic; consider f.e. `clone $obj`, which is quite similar to `new > klass`. >
Thanks for the feedback Claude. I think you make a compelling case, and have updated the RFC to use "new (expr)" and "$x instanceof (expr)" syntax instead. Regards, Nikita

Nikita Popov

6 years ago
On Tue, Jan 7, 2020 at 11:23 AM Nikita Popov <nikita.ppv@gmail.com> wrote:
> Hi internals, > > I'd like to propose a small RFC, which addresses a few minor issues that > have not been handled by the original "uniform variable syntax" RFC: > > https://wiki.php.net/rfc/variable_syntax_tweaks > > This is all about edge cases of edge cases, of course. I think the only > part here that is not entirely straightforward and may need some discussion > is how arbitrary expression support for instanceof should be handled. > > Regards, > Nikita >
Heads up: I plan to start voting on this RFC tomorrow. Since the original RFC, the syntax for new/instanceof has been changed to use (expr) instead of {expr}, in line with discussion feedback. Nikita