Date: Mon, 11 Nov 2024 02:12:12 -0700
> The standard needs to show discipline because users won't.
I've worked extensively with game engine technologies where we've explored
reflection done in user space for well over a decade now. While I can't
speak to all game engines, I've used several large commercial ones, and a
couple large internal engines. For the most part reflection *must* encompass
public, private, and protected members, and failure to do so would break
tooling and cause huge surprises to users when member field visibility
changes. Reflection is typically built on custom preprocessors, and to a
lesser extent, compiler-assisted tooling like clang. Reflection is used to
surface editable properties to artists and content creators in tools,
serialize payloads to disk, serialize networked properties over the network
interface, and other such use cases. The visibility of a property/field or
even member function to other C++ interfaces is an orthogonal concern to
visibility in these other externally-facing use cases. I actually can't
think of a single moment where I cared to iterate over specifically *public
*fields of a class. If we needed to control visibility, this was typically
done with user-defined attributes we'd attach to the properties themselves.
In short, I don't think the desire or need to bypass the C++ access
specifiers has anything to do with a lack of "discipline." They are not the
same problem, and visibility in the C++ domain is not to be conflated with
visibility in the exterior domain (which is what reflection is intended to
tie us to). Here is a page that lists a number of property specifiers used
in Unreal to annotate how fields are exposed to other bits of tooling:
https://benui.ca/unreal/uproperty/. The official documentation is here (
https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-uproperties#propertyspecifiers)
but Ben's page is a bit more illustrative of the end effect.
I understand that game engines are but one slice of the pie among a variety
of C++ users in our community, but thought I'd weigh in briefly because I
believe game developers likely have clocked more hours with reflection in
general, with perhaps more intensive needs (not as a general rule, this is
a personal observation, I'm sure there are exceptions).
Best,
Jeremy
On Mon, Nov 11, 2024 at 1:56 AM Corentin via SG7 <sg7_at_[hidden]>
wrote:
>
>
> On Mon, Nov 11, 2024 at 7:09 AM Oliver Hunt via Ext <ext_at_[hidden]>
> wrote:
>
>>
>>
>> > On Nov 10, 2024, at 7:46 PM, Peter Dimov via Ext <ext_at_[hidden]>
>> wrote:
>> >
>> >> https://isocpp.org/files/papers/P3493R0.html
>> >
>> > "There are suggestions that it's enough to access-control data, and
>> leave metadata (types, names, cardinalities) fully-accessible.
>> >
>> > That suggestion also doesn't model how the language works. Access
>> controls control metadata as well as data. You can't name the data members
>> of PolarRep/VectorRep/C1/C2/C3/C4, you can't get their types, you can't
>> count how many such members exist; you do not have access to the metadata
>> any more than you have access to the data.
>> >
>> > And of course you don't."
>> >
>> > I have a few things to say about this.
>> >
>> > First, at present, "of course" you don't have access
>> > to anything reflected. That's exactly what we're trying
>> > to fix with 2996.
>> >
>> > Second, the principle here is that if I can physically see
>> > in the source code that the class has private members of
>> > types C1, C2, C3, then the program should also be able to
>> > see that, using the reflection facilities. If not, we don't
>> > really have reflection, and we'll have to use other means,
>> > such as parsing the source with libclang, or parsing the
>> > debug info, and so on. Basically, what we do today and
>> > hope we wouldn't need to do tomorrow.
>>
>>
>> Entirely in agreement here - restricting access to private fields from
>> being accessible via reflection based on source level annotations that
>> exist to stop developers from misusing members and data that aren’t
>> intended to be directly accessed outside of the class is good defensive
>> practice. However limiting _reflection_ from examining those data is
>> severely limiting to many basic uses of reflection, a canonical example is
>> serialization, but there are numerous others.
>>
>
> There aren't that many (and I somewhat doubt automatic serialization will
> be used that often as non-toy software cares about providing stable formats
> that are often independent from in-memory representation).
> But mostly, that is useful or cool ought to be a secondary concern to
> making sure introducing reflection is not going to make non-toy C++
> programs, especially in large teams, companies, and in projects with third
> party dependencies maintainable over time.
> The idea that the developer application ought to have full control and
> power is alluring but we know it doesn't work in practice.
>
> No library developer will want users to reflect on their non-public
> interfaces. The standard needs to show discipline because users won't.
>
>
>> In the context of P2719, having the ability to (transitively) introspect
>> all fields of a type is useful for the purpose of an allocator wanting to
>> reason about the properties of a type. Precluding access to the actual
>> content of a type drastically limits the use of reflection for this purpose
>> (and forces developers to rely on compiler extensions, manual annotations,
>> manual adoption, and or external tools like libclang, etc to provide the
>> necessary information).
>>
>> —Oliver
>>
>>
>>
>> _______________________________________________
>> Ext mailing list
>> Ext_at_[hidden]
>> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/ext
>> Link to this post: http://lists.isocpp.org/ext/2024/11/23799.php
>>
> --
> SG7 mailing list
> SG7_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg7
>
I've worked extensively with game engine technologies where we've explored
reflection done in user space for well over a decade now. While I can't
speak to all game engines, I've used several large commercial ones, and a
couple large internal engines. For the most part reflection *must* encompass
public, private, and protected members, and failure to do so would break
tooling and cause huge surprises to users when member field visibility
changes. Reflection is typically built on custom preprocessors, and to a
lesser extent, compiler-assisted tooling like clang. Reflection is used to
surface editable properties to artists and content creators in tools,
serialize payloads to disk, serialize networked properties over the network
interface, and other such use cases. The visibility of a property/field or
even member function to other C++ interfaces is an orthogonal concern to
visibility in these other externally-facing use cases. I actually can't
think of a single moment where I cared to iterate over specifically *public
*fields of a class. If we needed to control visibility, this was typically
done with user-defined attributes we'd attach to the properties themselves.
In short, I don't think the desire or need to bypass the C++ access
specifiers has anything to do with a lack of "discipline." They are not the
same problem, and visibility in the C++ domain is not to be conflated with
visibility in the exterior domain (which is what reflection is intended to
tie us to). Here is a page that lists a number of property specifiers used
in Unreal to annotate how fields are exposed to other bits of tooling:
https://benui.ca/unreal/uproperty/. The official documentation is here (
https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-uproperties#propertyspecifiers)
but Ben's page is a bit more illustrative of the end effect.
I understand that game engines are but one slice of the pie among a variety
of C++ users in our community, but thought I'd weigh in briefly because I
believe game developers likely have clocked more hours with reflection in
general, with perhaps more intensive needs (not as a general rule, this is
a personal observation, I'm sure there are exceptions).
Best,
Jeremy
On Mon, Nov 11, 2024 at 1:56 AM Corentin via SG7 <sg7_at_[hidden]>
wrote:
>
>
> On Mon, Nov 11, 2024 at 7:09 AM Oliver Hunt via Ext <ext_at_[hidden]>
> wrote:
>
>>
>>
>> > On Nov 10, 2024, at 7:46 PM, Peter Dimov via Ext <ext_at_[hidden]>
>> wrote:
>> >
>> >> https://isocpp.org/files/papers/P3493R0.html
>> >
>> > "There are suggestions that it's enough to access-control data, and
>> leave metadata (types, names, cardinalities) fully-accessible.
>> >
>> > That suggestion also doesn't model how the language works. Access
>> controls control metadata as well as data. You can't name the data members
>> of PolarRep/VectorRep/C1/C2/C3/C4, you can't get their types, you can't
>> count how many such members exist; you do not have access to the metadata
>> any more than you have access to the data.
>> >
>> > And of course you don't."
>> >
>> > I have a few things to say about this.
>> >
>> > First, at present, "of course" you don't have access
>> > to anything reflected. That's exactly what we're trying
>> > to fix with 2996.
>> >
>> > Second, the principle here is that if I can physically see
>> > in the source code that the class has private members of
>> > types C1, C2, C3, then the program should also be able to
>> > see that, using the reflection facilities. If not, we don't
>> > really have reflection, and we'll have to use other means,
>> > such as parsing the source with libclang, or parsing the
>> > debug info, and so on. Basically, what we do today and
>> > hope we wouldn't need to do tomorrow.
>>
>>
>> Entirely in agreement here - restricting access to private fields from
>> being accessible via reflection based on source level annotations that
>> exist to stop developers from misusing members and data that aren’t
>> intended to be directly accessed outside of the class is good defensive
>> practice. However limiting _reflection_ from examining those data is
>> severely limiting to many basic uses of reflection, a canonical example is
>> serialization, but there are numerous others.
>>
>
> There aren't that many (and I somewhat doubt automatic serialization will
> be used that often as non-toy software cares about providing stable formats
> that are often independent from in-memory representation).
> But mostly, that is useful or cool ought to be a secondary concern to
> making sure introducing reflection is not going to make non-toy C++
> programs, especially in large teams, companies, and in projects with third
> party dependencies maintainable over time.
> The idea that the developer application ought to have full control and
> power is alluring but we know it doesn't work in practice.
>
> No library developer will want users to reflect on their non-public
> interfaces. The standard needs to show discipline because users won't.
>
>
>> In the context of P2719, having the ability to (transitively) introspect
>> all fields of a type is useful for the purpose of an allocator wanting to
>> reason about the properties of a type. Precluding access to the actual
>> content of a type drastically limits the use of reflection for this purpose
>> (and forces developers to rely on compiler extensions, manual annotations,
>> manual adoption, and or external tools like libclang, etc to provide the
>> necessary information).
>>
>> —Oliver
>>
>>
>>
>> _______________________________________________
>> Ext mailing list
>> Ext_at_[hidden]
>> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/ext
>> Link to this post: http://lists.isocpp.org/ext/2024/11/23799.php
>>
> --
> SG7 mailing list
> SG7_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg7
>
Received on 2024-11-11 09:12:23