Date: Thu, 27 Jun 2024 14:59:37 +0200
Hello,
sorry for coming a bit late to the party, but I read P2996R3 and was
thinking a bit about the syntax. Is it reasonable for me to feel that,
maybe, ^ and [:...:] would be better if switched?
To me, the reflection operator signifies a form of quotation - you no
longer talk about a thing, but about "thing". Sure, "reflexpr" is a
mouthful, but it also has the advantage of syntactically enclosing its
operand, like a quotation would do. Conversely, enclosing syntax is already
considered with ^{...} and potential ^(...), but that is not something one
would expect from a normal unary operator, such as *x being the same as
*(x). On the other hand, there is a precedent of this kind for enclosing
syntax, where e.g. decltype(x) is different from decltype((x)). Then there
is the matter of length - ^S is well and readable, but ^struct S is already
a bit strange, and what about ^decltype(...) or ^struct { ... }? One might
wish to use an enclosing syntax here simply to communicate what is
happening, which also has the advantage of potentially enclosing whole
declarations and not just identifiers. Lastly, operator^ is not really
overloadable in this situation, since it operates directly on syntax,
unlike all other similar operators (the only exception that comes to my
mind is &S::x being different from &(S::x), but that could be excused as a
syntax quirk that could be eventually remedied).
On the other hand, "splicing" is a true unary operation, taking an
expression of a single std::meta::info. There is no difference between
[:x:] and [:(x):], so why the need to always enclose the expression this
way? There are no other situations in the language like this, not even in
cases where type names or dependent types are heavily involved. The
situation where this is useful are nested names, since, say ^x::n would
have issues with priority, and (^x)::n needs the recognition of
parentheses, but even that could be fixed ‒ there is "->" as a counterpart
to ".", so why not have ==> as an analogous counterpart to "::"? Then x==>n
could be thought of as (^x)::n without having to define (^x). Lastly, it
would be weird to overload [:...:] as an enclosing operator, unlike ^ or
similar.
All in all, I view these two operations as very analogous to & and *, just
using an abstract "compile-time reference" to an entity instead of a
concrete address, so I would not be opposed at all to both using a
single-character operator for it (like say @ and ^ to look like pointers in
Pascal), but I really feel this choice of "wrap using a single character
and unwrap using special brackets" is the most confusing choice of all. I
have also taken a look at the alternative syntax ideas, and I quite like
using $ for "splicing" (reminds me of PHP's variable variables and calls),
but I feel that if $<...> is possible to use for the complicated cases when
lowering, so too must there be something similar for lifting, like @ and
@<...> (^<...> would be too spiky). Maybe that would be the best, for
symmetry.
Thank you for your opinions!
sorry for coming a bit late to the party, but I read P2996R3 and was
thinking a bit about the syntax. Is it reasonable for me to feel that,
maybe, ^ and [:...:] would be better if switched?
To me, the reflection operator signifies a form of quotation - you no
longer talk about a thing, but about "thing". Sure, "reflexpr" is a
mouthful, but it also has the advantage of syntactically enclosing its
operand, like a quotation would do. Conversely, enclosing syntax is already
considered with ^{...} and potential ^(...), but that is not something one
would expect from a normal unary operator, such as *x being the same as
*(x). On the other hand, there is a precedent of this kind for enclosing
syntax, where e.g. decltype(x) is different from decltype((x)). Then there
is the matter of length - ^S is well and readable, but ^struct S is already
a bit strange, and what about ^decltype(...) or ^struct { ... }? One might
wish to use an enclosing syntax here simply to communicate what is
happening, which also has the advantage of potentially enclosing whole
declarations and not just identifiers. Lastly, operator^ is not really
overloadable in this situation, since it operates directly on syntax,
unlike all other similar operators (the only exception that comes to my
mind is &S::x being different from &(S::x), but that could be excused as a
syntax quirk that could be eventually remedied).
On the other hand, "splicing" is a true unary operation, taking an
expression of a single std::meta::info. There is no difference between
[:x:] and [:(x):], so why the need to always enclose the expression this
way? There are no other situations in the language like this, not even in
cases where type names or dependent types are heavily involved. The
situation where this is useful are nested names, since, say ^x::n would
have issues with priority, and (^x)::n needs the recognition of
parentheses, but even that could be fixed ‒ there is "->" as a counterpart
to ".", so why not have ==> as an analogous counterpart to "::"? Then x==>n
could be thought of as (^x)::n without having to define (^x). Lastly, it
would be weird to overload [:...:] as an enclosing operator, unlike ^ or
similar.
All in all, I view these two operations as very analogous to & and *, just
using an abstract "compile-time reference" to an entity instead of a
concrete address, so I would not be opposed at all to both using a
single-character operator for it (like say @ and ^ to look like pointers in
Pascal), but I really feel this choice of "wrap using a single character
and unwrap using special brackets" is the most confusing choice of all. I
have also taken a look at the alternative syntax ideas, and I quite like
using $ for "splicing" (reminds me of PHP's variable variables and calls),
but I feel that if $<...> is possible to use for the complicated cases when
lowering, so too must there be something similar for lifting, like @ and
@<...> (^<...> would be too spiky). Maybe that would be the best, for
symmetry.
Thank you for your opinions!
Received on 2024-06-27 12:59:54