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