Comment #0 by qs.il.paperinik — 2023-05-08T16:31:32Z
The `child` trait is a reflection tool. It should **not** respect visibility (in the second parameter, i.e. the alias of a member function). If respecting visibility is desired, `getVisibility` can be used. This is consistent with other reflection traits, the reason being that a library that uses reflection may be passed a private symbol in the module in which it is defined.
Visibility is (correctly) bypassed when the address of the expression is taken.
Example (suitable for run.dlang.io):
```d
--- a.d
module a;
struct S
{
private void f(int i)
{
import std.stdio;
writeln("S.f(", i, ")");
}
}
alias publicAlias = S.f;
--- playground.d
#line 17 "playground.d"
import a;
void main()
{
S s;
s.f(0); // okay: fails because `f` is private
__traits(child, s, publicAlias)(42); // bug: fails
(&__traits(child, s, publicAlias))(42); // okay
}
```d
Comment #1 by razvan.nitu1305 — 2023-05-09T11:33:17Z
> This is consistent with other reflection traits
Which ones? I tried getMember and that doesn't bypass private.
I would argue that this is intended behavior and if the opposite occurs for other traits then that is the bug.
Comment #2 by qs.il.paperinik — 2023-05-09T15:37:33Z
> I would argue that this is intended behavior and if the opposite occurs for other traits then that is the bug.
I strongly disagree.
If you were right, that would mean that you cannot e.g. create a serialization library that can serialize private data members.
A module could reasonably pass a private symbol as an argument to an `alias` parameter of a template imported from another module. That template should be able to do its job, regardless whether the symbol is private.
> Which ones?
* `getProtection` for a trivial one.
* `getOverloads` allows accessing private overloads in a private aggregate
* `hasMember` and `allMembers` returns/lists private members
* `hasCopyConstructor` does not fail if the argument is an alias to a private struct
I didn’t check all of them, just a sample.
> I tried `getMember` and that doesn't bypass private.
I have no idea what you tried, but in my tests, it does.
Here is what I tried (suitable for run.dlang.io):
```d
--- a.d
#line 3 "a.d"
private struct _S
{
private int x;
private void f() @safe {}
private static int f(int x) @safe pure => x;
}
// only way to access anything in this module:
alias S = _S;
--- playground.d
#line 16 "playground.d"
import a;
void main()
{
S s;
static foreach (ov; __traits(getOverloads, s, "f"))
{
static if (is(typeof(ov(0))))
{
ov(0);
}
}
static assert(__traits(hasMember, S, "f"));
static assert(__traits(hasMember, s, "f"));
static assert(!__traits(compiles, s.x = 2 )); // x is private
__traits(getMember, s, "x") = 2;
static assert(!__traits(compiles, assert(s.x == 2) )); // x is private
assert(__traits(getMember, s, "x") == 2);
static assert(__traits(getProtection, S) == "private");
static assert(__traits(getProtection, __traits(getMember, s, "x")) == "private");
}
```
Comment #3 by robert.schadek — 2024-12-13T19:28:47Z