Re: [RFC] Variable syntax tweaks
| From: | Claude Pache | Date: | Thu, 16 Jan 2020 09:12:41 +0000 |
| Subject: | Re: [RFC] Variable syntax tweaks | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-108165@lists.php.net to get a copy of this message | ||
> 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