C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Simplified reflection with tuples

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Wed, 3 Jan 2024 14:56:19 -0500
On Wed, Jan 3, 2024 at 2:05 PM Franklin Yang via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>
> My proposal was referring to the (much older) Reflection TS 23619. I was unaware of P1240 and P2996 which already addressed my main concern with syntax in Reflection TS. The argument for a single reflection type is sound and not something I had considered, but this does not contradict the main point of my proposal.
>
> I do still believe my point regarding tuples is still valid. P1240/2996 uses a custom scalar type as the "reflection type" and a new splicing syntax to perform operations on this type.

The "splicing" syntax is for reification: the transformation of a
reflection *value* back into the thing it represents. You can perform
plenty of operations on a reflection value that don't involve
splicing.

And note that I said "reflection value", not "type". You're thinking
too much in template metaprogramming terms, not in constexpr coding
terms. All reflection values are of the same type, which is a scalar
type distinct from other types. It's the *value* of a reflection type
that determines what entity it reflects over.

> While powerful, it comes at the expense of being a completely new language feature, and also seems to have difficulties with functions (due to not having a convenient, "lossless" way to store functions as a type, correct me if I'm wrong).

Why would you want to store a function as a type? Again, you're
thinking too much in terms of template metaprogramming.

> If constexpr tuples are used instead, no new syntax for dealing with reflection objects is necessary, and existing approaches to tuples will also work for reflection.

But the "existing approaches" are all painful and difficult to use.
`constexpr` coding is way easier to work with than the template
metaprogramming approaches you have to use when dealing with `tuple`s.

Also, a `tuple` interface only makes sense for reflecting over the
contents of an entity. Getting the properties of the entity itself
(name, etc) wouldn't be available. After all, two different structs
that have the same members are still different structs.

> Due to this library requirement, this also means ^/reflexpr will be unavailable entirely without <reflect> (and <reflect> also includes <tuple>).
>
> On the topic of ^ and reflexpr, I believe a new operator ^ for reflection is unnecessary. The authors of P1240 cite that "with months of practice with implementations that used reflexpr(...) we experienced consistent feedback that that syntax is too “heavy”," but in casual use outside deliberately using reflection, I do not believe its usage to be common enough to justify this change. Apart from not burning additional syntax, reflexpr also has the advantage of being easier to understand for the untrained, and also avoids all discussion of precedence and overloading due to not being an operator.

`reflexpr` would also be an operator. Just because it's spelled with
words doesn't mean it isn't an operator. Issues of precedence and
overloading would still be there. operator `co_await` can be
overloaded, but only because it's allowed to be; operator `...` cannot
be overloaded. So there's no reason why `^` could not be a
non-overloadable operator.

Received on 2024-01-03 19:56:30