Thread overview
Why can we not use __traits across protection?
Apr 02, 2019
Alex
Apr 02, 2019
drug
Apr 03, 2019
Alex
Apr 03, 2019
drug
Apr 03, 2019
Atila Neves
Apr 15, 2019
Adam D. Ruppe
April 02, 2019
Module X:

class x
{
   private int x;
}

Module Y:

import X;

moduleName!(x.x);

or

__traits(getProtection, x.x);

Deprecation: `X.x.x.x` is not visible from module `Y`
Error: class `X.x.x` member `x` is not accessible

My use case is a little more complicated but I have two issues.


1: I have to import the module even though the type passed is valid(I'm using templates which are passed the type with a module import and I'd expect the module import to be "passed" along with the type so that I don't have to import it to use __traits or reflection.

2. If a member is protected then __traits and others fails. This makes absolutely no sense. Protection is used for run time, not compile time. What is strange is private methods give a deprecation warning but private fields give a deprecation error.


April 02, 2019
On 02.04.2019 17:56, Alex wrote:
> Module X:
> 
> class x
> {
>     private int x;
> }
> 
> Module Y:
> 
> import X;
> 
> moduleName!(x.x);
> 
> or
> 
> __traits(getProtection, x.x);
> 
> Deprecation: `X.x.x.x` is not visible from module `Y`
> Error: class `X.x.x` member `x` is not accessible
> 
> My use case is a little more complicated but I have two issues.
> 
> 
> 1: I have to import the module even though the type passed is valid(I'm using templates which are passed the type with a module import and I'd expect the module import to be "passed" along with the type so that I don't have to import it to use __traits or reflection.
> 
> 2. If a member is protected then __traits and others fails. This makes absolutely no sense. Protection is used for run time, not compile time. What is strange is private methods give a deprecation warning but private fields give a deprecation error.
> 
> 

Yes, it's known issue. I've spent rather much time to manage this. I do something like https://github.com/drug007/asdf/blob/the_last_changes/source/asdf/serialization.d#L3008 (this branch is not merged upstream yet)
April 03, 2019
On Tuesday, 2 April 2019 at 15:50:29 UTC, drug wrote:
> On 02.04.2019 17:56, Alex wrote:
>> Module X:
>> 
>> class x
>> {
>>     private int x;
>> }
>> 
>> Module Y:
>> 
>> import X;
>> 
>> moduleName!(x.x);
>> 
>> or
>> 
>> __traits(getProtection, x.x);
>> 
>> Deprecation: `X.x.x.x` is not visible from module `Y`
>> Error: class `X.x.x` member `x` is not accessible
>> 
>> My use case is a little more complicated but I have two issues.
>> 
>> 
>> 1: I have to import the module even though the type passed is valid(I'm using templates which are passed the type with a module import and I'd expect the module import to be "passed" along with the type so that I don't have to import it to use __traits or reflection.
>> 
>> 2. If a member is protected then __traits and others fails. This makes absolutely no sense. Protection is used for run time, not compile time. What is strange is private methods give a deprecation warning but private fields give a deprecation error.
>> 
>> 
>
> Yes, it's known issue. I've spent rather much time to manage this. I do something like https://github.com/drug007/asdf/blob/the_last_changes/source/asdf/serialization.d#L3008 (this branch is not merged upstream yet)


private template isPublic(alias aggregate, string member)
{
	static if (!is(Identity!(__traits(getMember, aggregate, member))) &&
		       __traits(compiles, { auto s = __traits(getProtection, __traits(getMember, aggregate, member)); }))
			enum isPublic = !__traits(getProtection, __traits(getMember, aggregate, member)).privateOrPackage;
	else
		enum isPublic = false;
}

How does that work to get around the problem? It seems all it does is return false if it fails and so assumes it to be private...

but this doesn't work in other traits that fail.
April 03, 2019
On 03.04.2019 3:57, Alex wrote:
> On Tuesday, 2 April 2019 at 15:50:29 UTC, drug wrote:
> 
> 
> private template isPublic(alias aggregate, string member)
> {
>      static if (!is(Identity!(__traits(getMember, aggregate, member))) &&
>                 __traits(compiles, { auto s = __traits(getProtection, __traits(getMember, aggregate, member)); }))
>              enum isPublic = !__traits(getProtection, __traits(getMember, aggregate, member)).privateOrPackage;
>      else
>          enum isPublic = false;
> }
> 
> How does that work to get around the problem? It seems all it does is return false if it fails and so assumes it to be private...
> 
> but this doesn't work in other traits that 

Ok, my usecase is the following - I need to process all members of some aggregate. But using traits with not accessible members fails. So I use `isPublic` to filter out not accessible members and then use other traits to process accessible members.
April 03, 2019
On Tuesday, 2 April 2019 at 14:56:38 UTC, Alex wrote:
> Module X:
>
> class x
> {
>    private int x;
> }
>
> Module Y:
>
> import X;
>
> moduleName!(x.x);
>
> or
>
> __traits(getProtection, x.x);
>
> Deprecation: `X.x.x.x` is not visible from module `Y`
> Error: class `X.x.x` member `x` is not accessible
>
> My use case is a little more complicated but I have two issues.

__traits(getProtection, __traits(getMember, x, "x")) works. You just can't spell "x.x" anywhere.

>
> 1: I have to import the module even though the type passed is valid(I'm using templates which are passed the type with a module import and I'd expect the module import to be "passed" along with the type so that I don't have to import it to use __traits or reflection.

I used to think this but it's not actually needed.


> 2. If a member is protected then __traits and others fails. This makes absolutely no sense. Protection is used for run time, not compile time. What is strange is private methods give a deprecation warning but private fields give a deprecation error.

See above.


April 15, 2019
On 4/3/19 5:19 AM, Atila Neves wrote:
> On Tuesday, 2 April 2019 at 14:56:38 UTC, Alex wrote:
>> Module X:
>>
>> class x
>> {
>>    private int x;
>> }
>>
>> Module Y:
>>
>> import X;
>>
>> moduleName!(x.x);
>>
>> or
>>
>> __traits(getProtection, x.x);
>>
>> Deprecation: `X.x.x.x` is not visible from module `Y`
>> Error: class `X.x.x` member `x` is not accessible
>>
>> My use case is a little more complicated but I have two issues.
> 
> __traits(getProtection, __traits(getMember, x, "x")) works. You just can't spell "x.x" anywhere.
> 

So this is quite unintuitive. The compiler should realize here you are just checking protection, and forego the protection check on the expression. I.e. there should be a special exception to visibility checking inside __traits(getProtection, ...).

-Steve
April 15, 2019
On Monday, 15 April 2019 at 14:55:36 UTC, Steven Schveighoffer wrote:
> So this is quite unintuitive. The compiler should realize here you are just checking protection, and forego the protection check on the expression.

So there was a PR pulled last week that exempts getMember from protection checks, which solves this (finally!) and makes private filtering a user concern for the traits now.

That is kinda cool. I got used to it the way before but this will prolly be more convenient overall.