Document #: | P3419 |
Date: | 2024-10-08 |
Project: | Programming Language C++ |
Audience: |
EWG |
Reply-to: |
Michael Levine <mlevine55@bloomberg.net> |
This paper presents a summary of reflection syntax options. Some of these options are activately under consideration, while others have already been discussed and dismissed. However, the reasons for their dismissal have not necessary been recorded in a central location showcasing their perceived advantages or disadvantages relative to other options. This paper intends to be a reference for such discussions. A specific non-goal of the paper is the promotion of a particular syntax.
#
|
Get Meta
|
Splice in Meta
|
---|---|---|
1 | @<foo |
@>foo |
2 | ^^foo |
[: foo :] |
3 | ^^foo |
,,foo |
4 | <-foo |
->foo |
5 | $$foo |
$foo |
6 | `foo | ,foo |
7 | ^foo |
[: foo :] |
8 | @<<foo |
>>@foo |
9 | @<-foo |
->@foo |
10 | <@foo |
@>foo |
11 | <@foo |
>@foo |
12 | &&foo |
&&>foo |
13 | :foo |
$foo |
14 | /foo |
\foo |
15 | ^^foo |
$$foo |
16 | ``foo | ,,foo |
17 | @<<foo |
@>>foo |
18 | @<-foo |
@->foo |
#
|
Syntax
|
---|---|
1 | ^^foo |
2 | ^foo |
3 | @<foo |
4 | @<<foo |
5 | @<-foo |
6 | <@foo |
7 | |foo |
8 | /foo |
9 | %foo |
10 | `foo |
11 | :foo |
12 | ~~foo |
13 | ^-foo |
14 | <-foo |
15 | -<foo |
16 | ^%foo |
17 | $$foo |
18 | &&foo |
19 | @foo |
20 | #foo |
21 | $foo |
22 | 'foo |
23 | =foo |
24 | ?foo |
25 | \foo |
26 | ^[foo] |
27 | ${foo} |
28 | $(foo) |
29 | /\foo |
30 | ``foo |
# 1:
^^foo
exclusive-or
.
An example is expr ^^ { return 1; }()
.# 2:
^foo
foo
.^
to both
introduce a block and as part of the syntax for “block types” [P3381R0]. With this extension, some
parses may not be able to be disambiguated. type-id(^ident)()
is ambiguous, and auto A = ^{ f(); };
with [P3294R1] is ambiguous [P3381R0].foo^
, which
is used as a type in other languages built on top of C++ such as
ObjectiveC++ [P3381R0] and the Microsoft .NET
extensions.# 3:
@<foo
fn<@<foo>
.# 4:
@<<foo
@<foo
.# 5:
@<-foo
-
sign.# 7:
|foo
if (|T == |U)
[P3381R0].# 8:
/foo
\
for code injection [P3381R0]./(/e)
and /(*e)
[P3381R0].# 9:
%foo
C<%T> c;
,
<%
is a
digraph for
{
. This
would require spaces or parentheses to get around this issue [P3381R0].# 10: `foo
# 11:
:foo
ex2 = Expr(:call, :+, 1 , 1)
to produce a Julia Expr type such as :(1 + 1)
[JuliaMeta].C<:T>
would not work because
<:
is a
digraph for
[
[P3381R0]. This can potentially be
remedied by being called as C<(:T)>
,
but this could leads to errors that are difficult to debug.[::foo:]
.# 12:
~~foo
foo
is an
integral expression, then
~~foo
means
to flip all of the bits and then flip them again.~
symbol.~
is
already a unary operator.# 13:
^-foo
-
symbol.# 14:
<-foo
<<-
from < <-
when used as a template argument as in fn<<-foo>
.-
symbol.# 18: &&foo
if (&&foo&& == &&foo&& && &&foo&& == &&foo&&)
where &&foo&&
is a reflection on a foo
reflection
type. This is comparing two reflections for equality.(&&foo&&)
.&&
is already used for logical AND
and
rvalue/forward references.# 19:
@foo
@
in
identifiers as an extension, so we wouldn’t be able to disambiguate
between reflecting on an identifier and actually being an identifier
[P3381R0].@property
,
@dynamic
,
@optional
,
etc). This also cannot be escaped since @(foo)
is a boxed expression and @[foo]
and @{foo}
are container literals [P3381R0].# 20: #foo
#define MACRO(x) do_something_with(#x)
already has meaning [P3381R0].# 21:
$foo
# 23:
=foo
# 24:
?foo
# 25: \foo
# 26: ^[foo]
# 27: ${foo}
$
in
identifiers as an extension [P3381R0].$
symbol is typically used as a splicing syntax in other languages, not as
the get meta syntax.# 28: $(foo)
$
in
identifiers as an extension [P3381R0].$
is
typically used as a splicing syntax in other languages, not as the get
meta syntax.# 29:
/\foo
^
symbol./\u0
will
have \u0
parsed as a UCN instead of
a reflection of u0
[P3381R0].# 30: ``foo
#
|
Syntax
|
---|---|
1 | [: foo :] |
2 | @>foo |
3 | @>>foo |
4 | @->foo |
5 | foo@> |
6 | (: foo :) |
7 | (^ foo ^) |
8 | (^_ foo _^) |
9 | ->foo |
10 | >-foo |
11 | $foo |
12 | $$foo |
13 | ,foo |
14 | ,,foo |
15 | &&>foo |
16 | foo@ |
17 | [| foo |] |
18 | ${foo} |
19 | $(foo) |
20 | ,@foo |
21 | foo&& |
22 | >>@foo |
23 | ->@foo |
# 6: (: foo :)
# 9:
->foo
fn<->foo>
.# 10:
>-foo
tvar<>-foo>-3
can be parsed as (tvar<> - foo) > -3
or as tvar<(>-foo)> - 3
.-
symbol for
code such as >-(-foo)
.# 11:
$foo
$
in
identifiers as an extension, so it can be hard to differentiate between
an identifier and reflecting on an identifier [P3381R0].# 13: ,foo
# 14: ,,foo
fn(,,bool, ,,int, ,,char)
.# 17: [| foo |]
# 18 ${foo}
$
in
identifiers as an extension [P3381R0].# 19 $(foo)
$
in
identifiers as an extension [P3381R0].# 20:
,@foo
#
|
Syntax
|
---|---|
1 | lift foo |
2 | lift(foo) |
3 | reflexpr foo |
4 | reflexpr(foo) |
5 | refl foo |
6 | refl(foo) |
7 | ref foo |
8 | ref(foo) |
9 | meta foo |
10 | meta(foo) |
11 | symbol foo |
12 | symbol(foo) |
13 | syntax foo |
14 | syntax(foo) |
15 | expr foo |
16 | expr(foo) |
17 | reflect foo |
18 | reflect(foo) |
19 | metafy foo |
20 | metafy(foo) |
21 | metify foo |
22 | metify(foo) |
23 | inspect foo |
24 | inspect(foo) |
25 | reflectof foo |
26 | reflectof(foo) |
27 | reflof foo |
28 | reflof(foo) |
29 | metaof foo |
30 | metaof(foo) |
31 | std::meta::meta(foo) |
32 | std::meta::get(foo) |
33 | std::meta::parse(foo) |
# 4: reflexpr(foo)
# 15:
expr foo
Expr
data structure
definitions.expr foo
would
be an expression, and foo
is not
generally an expression.# 16: expr(foo)
Expr
data structure
definitions.
#
|
Syntax
|
---|---|
1 | splice foo |
2 | splice(foo) |
3 | splice_in foo |
4 | splice_in(foo) |
5 | eval foo |
6 | eval(foo) |
7 | evalmeta foo |
8 | evalmeta(foo) |
9 | unlift foo |
10 | unlift(foo) |
11 | demeta foo |
12 | demeta(foo) |
13 | unmeta foo |
14 | unmeta(foo) |
15 | unref foo |
16 | unref(foo) |
17 | deref foo |
18 | deref(foo) |
19 | unrefl foo |
20 | unrefl(foo) |
21 | derefl foo |
22 | derefl(foo) |
23 | value foo |
24 | value(foo) |
25 | getvalue foo |
26 | getvalue(foo) |
27 | unexpr foo |
28 | unexpr(foo) |
29 | deexpr foo |
30 | deexpr(foo) |
31 | dereflect foo |
32 | dereflect(foo) |
33 | unreflect foo |
34 | unreflect(foo) |
35 | demetafy foo |
36 | demetafy(foo) |
37 | unmetafy foo |
38 | unmetafy(foo) |
39 | unmetify foo |
40 | unmetify(foo) |
41 | uninspect foo |
42 | uninspect(foo) |
43 | deinspect foo |
44 | deinspect(foo) |
45 | dump foo |
46 | dump(foo) |
47 | unsyntax foo |
48 | unsyntax(foo) |
49 | desyntax foo |
50 | desyntax(foo) |
51 | desugar foo |
52 | desugar(foo) |
53 | unsymbol foo |
54 | unsymbol(foo) |
55 | desymbol foo |
56 | desymbol(foo) |
57 | unreflexpr foo |
58 | unreflexpr(foo) |
# 17:
deref foo
foo
, not splicing in its meta
value.# 18: deref(foo)
foo
, not splicing in its meta
value.# 58: unreflexpr(foo)
#
|
Syntax Type
|
---|---|
1 | Unary prefix operators |
2 | Bounded splice operators |
3 | Single character splice operators |
4 | Function keywords |
5 | Contextual keywords |
6 | Library functions |
# 1: Unary prefix operators
*(foo())
.# 2: Bounded splice operators
[:Cls::reflection_member:]::inner::member
,
which is easier to parse than $Cls::reflection_member::inner::member
.# 3: Single character splice operators
# 4: Function keywords
splice foo::bar::baz
.# 5: Contextual keywords
Some of the syntax ideas, as well as their respective advantages and disadvantages, are my own, but many others came from discussions with Alisdair Meredith and a number of my other colleagues and peers.