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.
}







Reply via email to