Overloads not returning appropriate info. [Field reflunkory]

Alex AJ at gmail.com
Mon Apr 8 14:39:03 UTC 2019


On Monday, 8 April 2019 at 12:26:28 UTC, Adam D. Ruppe wrote:
> On Sunday, 7 April 2019 at 17:42:58 UTC, Alex wrote:
>> That is blatantly wrong. The code works EXACTLY the same way 
>> with and without using stringof.
>
> In some cases, yeah. In the general case, no.
>
> Your import hack* is only there because of stringof. Using the 
> local symbol, there is no need to import the module. This means 
> you avoid name conflicts with local symbols (like I pointed out 
> in the linked post) and it has the potential to avoid 
> protection violation errors, since you are no longer getting 
> the symbol from your module; it is gotten somewhere else, 
> ideally from its own module, and passed to you, which is 
> allowed even for private or hidden symbols.
>
> It also just makes the code a lot simpler, so there's no more 
> need to jump through hoops to debug it.

But I've already said the point of using T.stringof is so that 
one gets what T is and that actually helps debugging. You don't 
think I didn't try using T first? Why would I type extra symbols 
if it work exactly fine the first time?

The reason I added `~T.stringof~` which is 11 more chars than T.` 
was precisely because the code wasn't working and I was trying to 
figure out why. to claim that it's absolutely wrong in all cases 
is ignorant.

I realize that in many cases it is unnecessary and in some cases 
it will break the code(requiring an import because one is not 
using the type but the id which is then hidden)...

But as I said, I did a search and replace that it didn't change 
squat as far as the code. The main issue was using that typeof 
which you didn't catch cause you were too busy trying to make an 
issue out of stringof.

The other issues either remain, even after using your "rule", or 
I had to refactor the code and use different traits(such as the 
one you recommended for fields).


My point is that you are going ape shit over using T.stringof, 
you posted no real reasons why it is absolutely unnecessary yet 
claimed was after I already shown that it has some use.

It's one thing to make a suggestion and say "You know, you don't 
have to use T.stringof since it will function better in general, 
try it without it and see if fixes your problems" rather than 
keep on beating a dead horse.


> * 
> https://github.com/IncipientDesigns/Dlang_Reflect/blob/master/mReflect.d#L61
>
>> I have removed all T.stringof's in the code and I still get 
>> the exact same errors.
>
> That's the first step. Then, you clean up the hacks that were 
> introduced to work around stringof's problems and get a better 
> design that actually works, like passing private members from 
> one module to another via alias parameters.

I don't know what you are talking bout passing private members 
from one module using alias parameters. There is only one module 
that does the reflection and all the "passing" of private 
parameters are done INSIDE that module.

If you mean that I should pass the initial class as an alias, 
well, I tried that initially and it worked for some things but 
failed for others so went back and forth between using alias and 
types. The problem is because there are issues in D's type system 
and when they create hard to track bug one has to screw with shit 
to figure out what is going on and that introduces dead ends 
which may or may not be modify the design incipiently... which is 
the whole damn reason I'm writing the reflection library in the 
first place... to avoid all these issues  with traits and provide 
a common interface...

I mean, half the shit in __traits looks like it could be in 
std.traits and there is no clear reason why there are two aspects 
of D that do essentially the same thing. Also there are many 
"holes" in traits that require compound solutions(such as filter 
members to specific types) which then creates ugly CT 
code(multiple nested loops).





>> one could just open the source if there was anything to "hide"
>
> That's not necessarily true, it is possible to have code 
> exclude private members. In fact, it is often considered good 
> practice to do that for library releases for encapsulation!

I'm not sure what you are talking about here. I assume you mean 
the body, which I'm not talking about. The body is irrelevant. 
You can't even get the body using __traits. I'm talking about if 
the symbol exists, private or not, one can see it in the source 
code since, for it to be marked private it must show up in the 
source. So, "private" does actually hide shit in the source code. 
It may hide the functionality/body/binary code, but marking a 
member private doesn't HIDE anything in the source.


>> Protection is a runtime thing(except for CTFE).
>
> Protection *only* exists at compile time - at runtime, there's 
> zero checks. There's nothing preventing you from passing a 
> pointer to a private member, for example.

No, you really are missing the point. Protection is a RUNTIME 
thing. Else one would just make all members public. Protection 
exists at compile time,obviously, to stop one from accessing 
members, but it stops those access at RUNTIME.

Meaning, the compiler says "Error, trying to access private 
member" and you can't even write code to access them so the code 
doesn't exist at runtime to access(although it can be hacked, 
yes, but it IS for runtime, it may exist only at CT but it is to 
modify runtime behavior).


What I'm talking about is compile time meta programming. You are 
inspecting private members at CT only for CT, not for 
runtime(although it can be used to modify runtime behavior, and 
it should be without problem).

For example, suppose one writes a wrapper around a class. Wrap!C. 
Why should Wrap!C fail(give compile time errors) for private 
members of C? Wrap!C would just ignore the private members(which 
it can do with __traits(compiles but it shouldn't get errors that 
prevent compilation)).

class C
{
    private X;
    int f;
}

D = Wrap!C;

Wrap builds

class D
{
    int f;
}

Wrap!C should have no problem building D, but now it gives 
deprecation errors, why(well, at least using one way)? It can 
manage the the check itself and exclude it but the code shouldn't 
break. Hell, even just a warning would be better.


> This is why __traits(getMember) fails the same as T.name, but 
> it is also the reason why there's hope to cheat here, at least 
> once you get a correct foundation laid, by using mixin 
> templates and/or passing aliases cross module.


You are going to have to explain to me what exactly you mean by 
passing aliases. Maybe I don't fully understand how D's type 
system works.  I assume by "passing aliases" you mean using alias 
parameters instead of type parameters for templates:

void foo(alias T)

vs

void foo(T)

second case only except types, first case accepts most other 
things.

If so, that is exactly what I did. Initially I did pass just T, 
since I was working with types, but that quickly failed and I 
switch all the reflects to alias T. That then failed though 
because I couldn't pass certain things. I initially used 
overloads to handle it but that caused problems, I then switched 
to using variadics, which seemed to help but wasn't ideal.

I suggest that if you are so passionate about my library that you 
go ahead and design one yourself and see how easy it is. You 
might understand certain issue better than me but I bet you run 
in to a few issues. Those issues may not throw a monkey wrench in 
to your flow since you might understand how to work around them 
easier(and hence not go off on tangents) but the main point here 
is that those issues should not exist.



For example, the main entry point in to the reflection library is 
this:

auto Reflect(T...)()
{		
	static foreach(t; ["class", "interface", "struct", "union", 
"function", "delegate", "enum"])
		mixin("static if (is"~cap(t)~"!(T)) { auto model = new 
c"~cap(t)~"Reflection(); model.Reflect!T(); } ");

	return model;
}


And it just delegates the call to the appropriate reflection 
handler. So to say I'm not passing around alias here, when every 
other reflect call uses alias(except the field and base handler 
which also passes the name of the field) doesn't make sense to me.

		static if (name != "")
		{
			// We let the base class do all work, but must pass in type 
and name separately
			super.Reflect!(T, name);

			Protection = __traits(getProtection, __traits(getMember, T, 
name));			


I have spend many hours trying to pass the "field" as an alias 
parameter but it never works. It either creates nonsense or 
fails. Building the type by name and importing it works... you 
can claim it is a hack but either you have to provide the correct 
way or accept it.

		static if (Ts.length > 1)
		{
			// Assume field or constructable name is being passed if more 
than one argument
			mixin(`import `~moduleName!(Ts[0])~`;`);	
			mixin(`alias T = `~(Ts[0]).stringof~`.`~Ts[1]~`;`);			
			


You can claim that my initial Reflect!C is a template that 
excludes in the module that contains C,which is not the case, it 
imports that. (C is defined in another module). Reflect then 
delegates to the other reflects. They will won't exist in the 
module where C is defined and so will still have the protection 
issues.


And if I change that stringof to not use it:

mixin(`alias T = Ts[0].`~Ts[1]~`;`);			

I get shitload of errors, and so in this case it actually works 
better.


mReflect.d-mixin-67(67): Deprecation: 
`mModel.cDerived!int.cDerived.testField2` is not visible from 
module `mReflect`
mReflect.d-mixin-67(67): Error: class 
`mModel.cDerived!int.cDerived` member `testField2` is not 
accessible

You can claim that if I passed by alias it should work... but I 
am passing by alias(if you mean what I said earlier).


I don't think you understand some subtle point here. You got way 
to fixated on stringof and maybe completely missed the original 
problem. That original problem may be due to a misunderstanding 
on my part but claiming stringof's are the source is moronic. I 
hope you can at least get over that issues. If what these issues 
are originating from some other problem then that should be 
addressed rather than making claims that are not founded. In the 
above example it proves that stringof actually functions when not 
using it doesn't(The protection issue gives an error).

I FULLY understand that I'm trying to access a private field. 
What I'm saying is that I'm only accessing it at CT(even though 
it is in CTFE) and so it shouldn't give me errors. (Maybe the 
protection should be checked not in the alias but where the alias 
is used, which may or may not help here).

What I don't understand is that you had access to all the code 
and could have spent a few minutes fixing it with your elite 
knowledge but chose to derail the thread in to meaningless things.

The proof that I'm right and you are wrong has been demonstrated 
by me by using your solution and showing that the errors still 
exist. You are the ones that claimed that all the errors were due 
to using stringof. I removed them and the errors persisted. 
Hence, they were not due to that. Now, you might be correct that 
it is due to "aliases" but I do pass by aliases so you are wrong 
again.

I don't know what else I can say about it. You are wrong, just 
accept it. You might be correct fundamentally but I think you 
failed to really look at the code and how it was put together or 
you didn't explain the real issue involved. Saying it is stringof 
or aliasing is easy to say but if it was so easy you could have 
easily downloaded the code and modified it in a few minutes and 
demonstrated with factual evidence the issues. You've actually 
wasted more time trying to defend your points(none of which I 
disagree with, I'm just disagreeing that they are the *source* of 
*all* the problems) than you could have spent fixing the code 
that you claim is broke and that are hacks.


I will iterate here once more, not that it matters, to be CLEAR:

1. Reflect is instantiated in the module main using the class C. 
C's private members are private to the module main. So all 
private members of C will not be accessible to anything in 
reflect no matter what! (unless there is some way to get them 
correctly)

2. All the Reflects use alias.

3. stringof is not the issue. It stems from two things. Issue 1 
and to help debug mixins easier.


I'm sure if I called Reflect in the module that C is defined in 
the errors would go away, but that requirement makes the library 
nearly useless.

My point is 1 should not exist when accessing private members at 
compile time. The protection check should pass and be delegated 
to code that is "written for runtime".

For example,

static foreach(m; __traits(allMembers, T)) // should not fail here
{
     writeln(T.m); // should fail here but we can use __traits to 
prevent this.
}









More information about the Digitalmars-d-learn mailing list