C++ Logo

sg7

Advanced search

Re: [SG7] Update: P1240R2 — Scalable Reflection

From: David Rector <davrec_at_[hidden]>
Date: Sat, 15 Jan 2022 14:45:19 -0500
> On Jan 15, 2022, at 2:34 PM, Daveed Vandevoorde via SG7 <sg7_at_[hidden]> wrote:
>
>
>
>> On Jan 15, 2022, at 1:39 PM, Peter Dimov via SG7 <sg7_at_[hidden] <mailto:sg7_at_[hidden]>> wrote:
>>
>> Daveed Vandevoorde wrote:
>>> Hello reflecting friends,
>>>
>>> (And Happy New Year!)
>>>
>>> I’ve uploaded on the 2022 Teleconferences wiki for SG-7 an updated version
>>> of P1240 (which has also been submitted for the next mailing).
>>>
>>> Changes include:
>>> — The syntax agreements that SG-7 voted through P2320 (e.g., prefix ^
>>> instead of reflexpr(…) to create reflections)
>>> — The proposed metafunctions now use span and string_view instead
>>> of vector and string
>>> — Various corrections and clarifications based on reader feedback and
>>> implementation experience
>>
>> I think that it might be worth discussing Matus's alternative representation
>> of reflections. Roughly, while P1240 has something equivalent to
>>
>> struct info { uintptr_t id; };
>>
>> Matus instead suggests (if I understand correctly)
>>
>> template<uintptr_t id> struct info {};
>>
>> This implies that one does
>>
>> constexpr info x = ^T;
>>
>> under P1240 and
>>
>> constexpr auto x = ^T;
>>
>> under the hypothetical alternative.
>>
>> The arguments against this are (again IIUC) performance - the latter
>> causes much more template instantiations because functions are like
>>
>> consteval some_func( auto refl );
>>
>> instead of
>>
>> consteval some_func( info refl );
>>
>> However, there's a difference in usability, too. In the first case, one can
>> always splice [:refl:] inside some_func (because it's an instantiation context),
>> whereas in the second case, one cannot.
>
>
> That’s a massive price to pay, though (_every_ reflection value costs a type instance). And if you’re willing to pay it, you can with P1240. You can write:
>
> template<info R> struct Refl { ... };
>
> and now you have that same capability.
>
> The reverse is not true.
>
> (You could also write:
>
> template<info refl> consteval some_func();
>
> which is slightly cheaper in terms of compilation resources and different notation.)
>
> Daveed
>

There is also the matter of a) iteration, and b) a more serious performance reason I have not seen mentioned elsewhere.

Iteration: special iteration mechanisms are required, unless you want to require a functional style as Matus’s implementation uses: see Andrew/Wyatt/Lock3’s `template for(auto …)` or `for(constexpr auto …)`, which instantiates each iteration. Non-range-based iteration (while statements, non-range for statements etc.) are almost certainly not feasible.

(Aside: for those interested in trying the `template for` with Matus’s implementation or other template-instantiation based implementations, I extracted it into a clean branch here:
https://github.com/drec357/llvm-project/tree/dwr-feature-template-for
And a merge of this with Matus’s implem and my string injection implem for code generation is her:
https://github.com/drec357/llvm-project/tree/meta-all
though it is a bit behind Matus’s.)

More serious performance reason:

First, suppose the reflection library included a queries for for fetching other declarations in the TU: say, it's sibling declarations and parent/children.

```
std::meta::get_next_decl(auto r)
std::meta::get_prev_decl(auto r)
std::meta::get_parent_decl(auto r)
std::meta::get_first_child_decl(auto r)
```

Now suppose a user decides they want to interface with reflection in an object-oriented style:
```
template<auto R>
struct DeclWrapper {
  auto nextDecl() { return DeclWrapper <decltype(std::meta::get_next_decl(R))>{}; }
  auto prevDecl() {…}
  auto getParent() { … }
  …
};

#include … // lots of stuff, big translation unit

int foo;
constexpr auto foorefl = DeclWrapper <decltype(^foo)>()>();
```

What happens when `foorefl` is instantiated?

First each member of DeclWrapper<decltype(^foo)> must be instantiated, which means we have to instantiate each return type, each of which is a DeclWrapper, which itself has to be instantiated, …

The chain reaction results in instantiations of DeclWrappers for *every single declaration in the translation unit*.

It is probably easier to just figure out narrow solutions resolving the precise deficiencies of value-based implementation than dealing with these issues.

>
>
> --
> SG7 mailing list
> SG7_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg7


Received on 2022-01-15 19:45:22