Date: Tue, 12 Nov 2024 20:45:06 +0100
On Tue, Nov 12, 2024, 20:31 Herb Sutter via SG7 <sg7_at_[hidden]>
wrote:
> Peter is saying all the things I want to say (and did say privately).
>
> > TL;DR if we want to prevent accidental misuses of this (unfortunately
> quite
> > common) sort, what we need is not a function to get the accessible
> nonstatic
> > data members, but a function that gets the nonstatic data members of a
> > struct-like type, and fails for non-struct-like types.
>
> +1, specifically the way I write that is this kind of pattern:
>
> for( auto&& m: t.get_member_objects() ) {
> if (!m.is_public()) { print_error("type must not have
> non-public
> data"); return; }
> :::
> }
>
> //
> https://github.com/hsutter/cppfront/blob/main/source/reflect.h2#L1046-L1049
>
> But even in that example link, that's Just One of Many Constraints a
> metafunction may enforce on a type that it has been given. From just that
> particular example, pasting:
>
> m.require( m.make_public(),
> "all struct members must be public");
> t.require( !mf.is_virtual(),
> "a struct may not have a virtual function");
> t.require( !mf.has_name("operator="),
> "a struct may not have a user-defined operator=");
>
> Serious question: Do we also want to add an API to return only nonvirtual
> functions? only non-customized assignment operators? only accessible
> members? it all seems very similar to me, in the reflection code I've
> written (including all of the above in that single example above) and all
> of
> these are driven by the use case of what code we're going to generate --
> and
> the code we're going to generate is the key, that's what is going to rely
> on
> the accessibility, non-virtuality, default-assignability, etc. for this
> particular use case we're writing the metafunction for.
>
> That is why I'm still open to examples, but so far I'm convinced that
> metadata != data, and we routinely need to *reflect* on all *metadata* (and
> can then filter exactly what we want no problem) even as I agree that we
> also want to be able to avoid *generating* code that bypasses *data*
> accessibility by default.
>
code is code.
if a developer relies on the names, presence, order, or shape of private
members of a third party library, it is not robust over time.
The long term ability to maintain large projects at scale trumps the very
mild inconvenience of more robust defaults.
If someone wants to reflect on private members, it should be explicit. it
has nothing to do with usage or usefulness, it has to do with ensuring a
healthy ecosystem in the presence of Hyrum's law, to the extent that we can.
> Adding a rule only for reflecting accessible data seems like targeting only
> one use case, and doing it at the wrong level (reading metadata, not
> accessing data).
>
> I understand smart people disagree, but wanted to reinforce Peter's points.
>
>
>
>
> > -----Original Message-----
> > From: SG7 <sg7-bounces_at_[hidden]> On Behalf Of Peter Dimov via
> SG7
> > Sent: Monday, November 11, 2024 10:37 AM
> > To: 'Ville Voutilainen' <ville.voutilainen_at_[hidden]>
> > Cc: Peter Dimov <pdimov_at_[hidden]>; sg7_at_[hidden]
> > Subject: Re: [isocpp-sg7] SG7 late paper P3493R0 - Ruminations on
> reflection
> > and access
> >
> > Ville Voutilainen wrote:
> > > For an illustrative one, it's far too easy to perform a SoA<=>AoS
> > > transformation on a type that doesn't actually expose those types and
> > > cardinalities, when most of your types are actually all-public structs
> > > and then you manage to throw not-all-public classes into the mix.
> >
> > I agree that it's easy to write a mostly-working AoS->SoA transformation
> that
> > only handles structs properly, and that the failure mode of using "get
> > accessible nonstatic data members" is better than the failure mode of
> using
> > "get all nonstatic data members".
> >
> > In the typical case of a type with only private data members, this would
> result
> > in an empty SoA type.
> >
> > Of course, you can see the question "do you really want your
> transformation
> > to depend on the place where you happen to invoke it" coming, right?
> >
> > This example is representative for a class of uses where what you really
> want
> > is not "only do this for the accessible members", and not even "only do
> this
> > for the public members", but "only do this for types that only have
> public
> > members, reject the rest".
> >
> > In addition, you also need to take care to reject unions, for which
> filtering by
> > accessibility won't help you at all, and, in the AoS->SoA case,
> bitfields.
> >
> > So filtering by accessibility, while somewhat of an improvement in
> catching
> > accidental misuses, isn't really what one would ideally want.
> >
> > Of course, if we really want to do this properly, one might argue that
> the
> > proper transformation of vector<X> for this
> >
> > class X
> > {
> > public:
> > int a;
> > protected:
> > int b;
> > private:
> > int c;
> > };
> >
> > isn't this
> >
> > struct X'
> > {
> > vector<int> a';
> > }
> >
> > but rather this
> >
> > class X'
> > {
> > public:
> > vector<int> a';
> > protected:
> > vector<int> b';
> > private:
> > vector<int> c';
> > };
> >
> > Others might argue, in contradiction to the above, that transforming
> > vector<complex<float>> into a struct is a perfectly cromulent use case.
> >
> > TL;DR if we want to prevent accidental misuses of this (unfortunately
> quite
> > common) sort, what we need is not a function to get the accessible
> nonstatic
> > data members, but a function that gets the nonstatic data members of a
> > struct-like type, and fails for non-struct-like types.
> >
> > --
> > SG7 mailing list
> > SG7_at_[hidden]
> > https://lists.isocpp.org/mailman/listinfo.cgi/sg7
>
> --
> SG7 mailing list
> SG7_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg7
>
wrote:
> Peter is saying all the things I want to say (and did say privately).
>
> > TL;DR if we want to prevent accidental misuses of this (unfortunately
> quite
> > common) sort, what we need is not a function to get the accessible
> nonstatic
> > data members, but a function that gets the nonstatic data members of a
> > struct-like type, and fails for non-struct-like types.
>
> +1, specifically the way I write that is this kind of pattern:
>
> for( auto&& m: t.get_member_objects() ) {
> if (!m.is_public()) { print_error("type must not have
> non-public
> data"); return; }
> :::
> }
>
> //
> https://github.com/hsutter/cppfront/blob/main/source/reflect.h2#L1046-L1049
>
> But even in that example link, that's Just One of Many Constraints a
> metafunction may enforce on a type that it has been given. From just that
> particular example, pasting:
>
> m.require( m.make_public(),
> "all struct members must be public");
> t.require( !mf.is_virtual(),
> "a struct may not have a virtual function");
> t.require( !mf.has_name("operator="),
> "a struct may not have a user-defined operator=");
>
> Serious question: Do we also want to add an API to return only nonvirtual
> functions? only non-customized assignment operators? only accessible
> members? it all seems very similar to me, in the reflection code I've
> written (including all of the above in that single example above) and all
> of
> these are driven by the use case of what code we're going to generate --
> and
> the code we're going to generate is the key, that's what is going to rely
> on
> the accessibility, non-virtuality, default-assignability, etc. for this
> particular use case we're writing the metafunction for.
>
> That is why I'm still open to examples, but so far I'm convinced that
> metadata != data, and we routinely need to *reflect* on all *metadata* (and
> can then filter exactly what we want no problem) even as I agree that we
> also want to be able to avoid *generating* code that bypasses *data*
> accessibility by default.
>
code is code.
if a developer relies on the names, presence, order, or shape of private
members of a third party library, it is not robust over time.
The long term ability to maintain large projects at scale trumps the very
mild inconvenience of more robust defaults.
If someone wants to reflect on private members, it should be explicit. it
has nothing to do with usage or usefulness, it has to do with ensuring a
healthy ecosystem in the presence of Hyrum's law, to the extent that we can.
> Adding a rule only for reflecting accessible data seems like targeting only
> one use case, and doing it at the wrong level (reading metadata, not
> accessing data).
>
> I understand smart people disagree, but wanted to reinforce Peter's points.
>
>
>
>
> > -----Original Message-----
> > From: SG7 <sg7-bounces_at_[hidden]> On Behalf Of Peter Dimov via
> SG7
> > Sent: Monday, November 11, 2024 10:37 AM
> > To: 'Ville Voutilainen' <ville.voutilainen_at_[hidden]>
> > Cc: Peter Dimov <pdimov_at_[hidden]>; sg7_at_[hidden]
> > Subject: Re: [isocpp-sg7] SG7 late paper P3493R0 - Ruminations on
> reflection
> > and access
> >
> > Ville Voutilainen wrote:
> > > For an illustrative one, it's far too easy to perform a SoA<=>AoS
> > > transformation on a type that doesn't actually expose those types and
> > > cardinalities, when most of your types are actually all-public structs
> > > and then you manage to throw not-all-public classes into the mix.
> >
> > I agree that it's easy to write a mostly-working AoS->SoA transformation
> that
> > only handles structs properly, and that the failure mode of using "get
> > accessible nonstatic data members" is better than the failure mode of
> using
> > "get all nonstatic data members".
> >
> > In the typical case of a type with only private data members, this would
> result
> > in an empty SoA type.
> >
> > Of course, you can see the question "do you really want your
> transformation
> > to depend on the place where you happen to invoke it" coming, right?
> >
> > This example is representative for a class of uses where what you really
> want
> > is not "only do this for the accessible members", and not even "only do
> this
> > for the public members", but "only do this for types that only have
> public
> > members, reject the rest".
> >
> > In addition, you also need to take care to reject unions, for which
> filtering by
> > accessibility won't help you at all, and, in the AoS->SoA case,
> bitfields.
> >
> > So filtering by accessibility, while somewhat of an improvement in
> catching
> > accidental misuses, isn't really what one would ideally want.
> >
> > Of course, if we really want to do this properly, one might argue that
> the
> > proper transformation of vector<X> for this
> >
> > class X
> > {
> > public:
> > int a;
> > protected:
> > int b;
> > private:
> > int c;
> > };
> >
> > isn't this
> >
> > struct X'
> > {
> > vector<int> a';
> > }
> >
> > but rather this
> >
> > class X'
> > {
> > public:
> > vector<int> a';
> > protected:
> > vector<int> b';
> > private:
> > vector<int> c';
> > };
> >
> > Others might argue, in contradiction to the above, that transforming
> > vector<complex<float>> into a struct is a perfectly cromulent use case.
> >
> > TL;DR if we want to prevent accidental misuses of this (unfortunately
> quite
> > common) sort, what we need is not a function to get the accessible
> nonstatic
> > data members, but a function that gets the nonstatic data members of a
> > struct-like type, and fails for non-struct-like types.
> >
> > --
> > SG7 mailing list
> > SG7_at_[hidden]
> > https://lists.isocpp.org/mailman/listinfo.cgi/sg7
>
> --
> SG7 mailing list
> SG7_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg7
>
Received on 2024-11-12 19:45:22