Access Rights (and how to break into a class)

140 views
Skip to first unread message

Ricardo Fabiano de Andrade

unread,
May 3, 2016, 12:52:56 AM5/3/16
to refle...@isocpp.org
Matus,

I had a lengthy discussion on this topic on the forum for future proposals. My goals were obtaining feedback for the following questions:
- Should the language have a mechanism for violating encapsulation?
- If so, should it be in reflection?

Long story short: the few people that had anything to say about it were either against any possibility of having such mechanism or if such thing was ever to be done, it should be only in the context of reflection.

Having this in mind, I'd like to provide some feedback on the existing direction of P0194R0 regarding this issue.

The goals are:
- makes violating encapsulation obvious, explicit and intentional
- make it easy to find ocurrences of such action in the code and forbid it if needed
- make it easy to distinct reflection operations done within the class and those done externally to it

Currently, accessing private/protected members would be possible by calling the meta-function 'get_all_data_members'.
Following this trend, we may have similar variations for member functions and nested types/typedefs.

A few issues to be discussed:
- naming: get_..._members vs. get_all_..._members. The names are not sufficiently distinct from each other to avoid mistakes.
- intention: get_all... does not make explicit the fact that it's occurring a violation of the class encapsulation.
- mixed responsibilities: get_all... is responsible for both listing members and violating encapsulation.

Suggestion 1 - pass the responsibility of violating encapsulation to the meta-acessors (getters):
- get_..._members only - listing always everything
- get_[public|protected|private]_pointer

Suggestion 2 - a totally separate meta-function (preferred):
- get_..._members only - listing always everything
- new 'ignore_access_specifier' returning an unrestricted version of the meta-object passed in
- get_pointer

What are your thoughts on this?

Cheers,
Ricardo

Axel Naumann

unread,
May 3, 2016, 2:56:33 AM5/3/16
to refle...@isocpp.org
Hi Ricardo,

Thanks for the input. I personally agree that we can come up with a better word than "all", but we are not yet at the bikeshedding stage.

I disagree that throwing in more complexity (suggestion 1 and 2) adds any benefit. To make things worse, limiting yourself to get_pointer is missing all the other details that are non-public (name, type of nested data members; nested types; etc); I could calculate the offset and types of each private data member; or rebuild a class with all-public data members (and then reinterpret_cast).

From what I saw in Jacksonville and before, everyone agrees that reflection of non-public members should be "greppable".

Cheers, Axel 
--
You received this message because you are subscribed to the Google Groups "SG 7 - Reflection" group.
To unsubscribe from this group and stop receiving emails from it, send an email to reflection+...@isocpp.org.
To post to this group, send email to refle...@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/reflection/.
For more options, visit https://groups.google.com/a/isocpp.org/d/optout.


-- 
--
ROOT - http://root.cern.ch
PH-SFT, CERN, 1211 Geneve 23, Switzerland
Tel: +41 22 7678225

Matus Chochlik

unread,
May 3, 2016, 7:09:46 AM5/3/16
to refle...@isocpp.org
Hi,

On Tue, May 3, 2016 at 8:55 AM, Axel Naumann <Axel.N...@cern.ch> wrote:

Thanks for the input. I personally agree that we can come up with a better word than "all", but we are not yet at the bikeshedding stage.

+1, but any suggestions for replacements of `get_*all*_data_members` are very welcome even at this stage :)


I was thinking about an optional parameter for the `get_*_members` operations:

`get_data_members<reflexpr(myclass), only_public_t>` // only public members

or simply

`get_data_members<reflexpr(myclass)>` // only public members

vs.

`get_data_members<reflexpr(myclass), including_nonpublic_t>` // all including non-public

This should make all such member enumerations greppable

But, I don't insist on the names of the optional arguments.


 
I disagree that throwing in more complexity (suggestion 1 and 2) adds any benefit. To make things worse, limiting yourself to get_pointer is missing all the other details that are non-public (name, type of nested data members; nested types; etc); I could calculate the offset and types of each private data member; or rebuild a class with all-public data members (and then reinterpret_cast).

I also don't think that #1 is very scalable. There will be reflections of other class members besides the data members with many different operations.
 

From what I saw in Jacksonville and before, everyone agrees that reflection of non-public members should be "greppable".
On 05/03/2016 06:52 AM, Ricardo Fabiano de Andrade wrote:
Matus,

I had a lengthy discussion on this topic on the forum for future proposals. My goals were obtaining feedback for the following questions:
- Should the language have a mechanism for violating encapsulation?
- If so, should it be in reflection?

Long story short: the few people that had anything to say about it were either against any possibility of having such mechanism or if such thing was ever to be done, it should be only in the context of reflection.

Having this in mind, I'd like to provide some feedback on the existing direction of P0194R0 regarding this issue.
Thanks for the effort!
 

The goals are:
- makes violating encapsulation obvious, explicit and intentional
- make it easy to find ocurrences of such action in the code and forbid it if needed
- make it easy to distinct reflection operations done within the class and those done externally to it

Currently, accessing private/protected members would be possible by calling the meta-function 'get_all_data_members'.
Following this trend, we may have similar variations for member functions and nested types/typedefs.

A few issues to be discussed:
- naming: get_..._members vs. get_all_..._members. The names are not sufficiently distinct from each other to avoid mistakes.
- intention: get_all... does not make explicit the fact that it's occurring a violation of the class encapsulation.
- mixed responsibilities: get_all... is responsible for both listing members and violating encapsulation.

Suggestion 1 - pass the responsibility of violating encapsulation to the meta-acessors (getters):
- get_..._members only - listing always everything
- get_[public|protected|private]_pointer
This is an interesting approach, but see the above. Also I don't see any value in distinguishing between private and protected members here. We are either breaking access restrictions or not.
If this was implemented, I would go for something like `get_pointer` vs. `get_nonpublic_pointer` (OK, nonpublic sounds little awkward).
 

Suggestion 2 - a totally separate meta-function (preferred):
- get_..._members only - listing always everything
- new 'ignore_access_specifier' returning an unrestricted version of the meta-object passed in
- get_pointer

I like this one more than #1 (but I'm not a big fan of the name of the operation).

So accessing a private member would become:

`get_pointer_v<ignore_access_specifier_t<get_element_t<reflexpr(myclass), 0>>>`

This is definitely greppable.

Matus

Ricardo Andrade

unread,
May 20, 2016, 5:20:55 PM5/20/16
to SG 7 - Reflection
Matus, Axel,
Back to this topic just for a few considerations.


On Tuesday, May 3, 2016 at 6:09:46 AM UTC-5, Matúš Chochlík wrote:
Hi,

On Tue, May 3, 2016 at 8:55 AM, Axel Naumann <Axel.N...@cern.ch> wrote:

Thanks for the input. I personally agree that we can come up with a better word than "all", but we are not yet at the bikeshedding stage.

+1, but any suggestions for replacements of `get_*all*_data_members` are very welcome even at this stage :)

 
Glad to hear that.
 

I was thinking about an optional parameter for the `get_*_members` operations:

`get_data_members<reflexpr(myclass), only_public_t>` // only public members

or simply

`get_data_members<reflexpr(myclass)>` // only public members

vs.

`get_data_members<reflexpr(myclass), including_nonpublic_t>` // all including non-public

This should make all such member enumerations greppable

But, I don't insist on the names of the optional arguments.


I don't think you should be concerned about adding this level of granularity on the "get_..._members" meta-functions.
Your initial idea seems more correct to me: either you want everything or you don't.

Instead, a facility to filter the returned MetaObjects based on one or more traits (such as is_private) would be much more interesting.
``
using only_public_integral_members = std::meta::only_t<
   std::meta::get_data_members_t<reflexpr(T)>, 
   std::meta::is_public,
   std::meta::type_trait_filter<std::is_integral>
>;
``
I hope the example gives an idea about what I'm suggesting here.
 
 
I disagree that throwing in more complexity (suggestion 1 and 2) adds any benefit. To make things worse, limiting yourself to get_pointer is missing all the other details that are non-public (name, type of nested data members; nested types; etc); I could calculate the offset and types of each private data member; or rebuild a class with all-public data members (and then reinterpret_cast).

I also don't think that #1 is very scalable. There will be reflections of other class members besides the data members with many different operations.
 

My favorite is also #2, so we're on the same page here.
 

From what I saw in Jacksonville and before, everyone agrees that reflection of non-public members should be "greppable".
On 05/03/2016 06:52 AM, Ricardo Fabiano de Andrade wrote:
Matus,

I had a lengthy discussion on this topic on the forum for future proposals. My goals were obtaining feedback for the following questions:
- Should the language have a mechanism for violating encapsulation?
- If so, should it be in reflection?

Long story short: the few people that had anything to say about it were either against any possibility of having such mechanism or if such thing was ever to be done, it should be only in the context of reflection.

Having this in mind, I'd like to provide some feedback on the existing direction of P0194R0 regarding this issue.
Thanks for the effort!
 

No problem. 

The goals are:
- makes violating encapsulation obvious, explicit and intentional
- make it easy to find ocurrences of such action in the code and forbid it if needed
- make it easy to distinct reflection operations done within the class and those done externally to it

Currently, accessing private/protected members would be possible by calling the meta-function 'get_all_data_members'.
Following this trend, we may have similar variations for member functions and nested types/typedefs.

A few issues to be discussed:
- naming: get_..._members vs. get_all_..._members. The names are not sufficiently distinct from each other to avoid mistakes.
- intention: get_all... does not make explicit the fact that it's occurring a violation of the class encapsulation.
- mixed responsibilities: get_all... is responsible for both listing members and violating encapsulation.

Suggestion 1 - pass the responsibility of violating encapsulation to the meta-acessors (getters):
- get_..._members only - listing always everything
- get_[public|protected|private]_pointer
This is an interesting approach, but see the above. Also I don't see any value in distinguishing between private and protected members here. We are either breaking access restrictions or not.
If this was implemented, I would go for something like `get_pointer` vs. `get_nonpublic_pointer` (OK, nonpublic sounds little awkward).
 

Unless, #2 becomes a challenge to implement, let's forget about #1. 

Suggestion 2 - a totally separate meta-function (preferred):
- get_..._members only - listing always everything
- new 'ignore_access_specifier' returning an unrestricted version of the meta-object passed in
- get_pointer

I like this one more than #1 (but I'm not a big fan of the name of the operation).

So accessing a private member would become:

`get_pointer_v<ignore_access_specifier_t<get_element_t<reflexpr(myclass), 0>>>`

This is definitely greppable.

Matus


As long such functionality exists, how to name it can be discussed.
It's important that the name suggests an uncommon and possible dangerous operation, be distinct enough to be easily greppable without false positives (such as reinterpret_cast) and, of course, remind of access restrictions or encapsulation.

 
Reply all
Reply to author
Forward
0 new messages