April 07, 2019
On Sunday, 7 April 2019 at 15:26:47 UTC, Adam D. Ruppe wrote:
> On Sunday, 7 April 2019 at 03:47:25 UTC, Alex wrote:
>> What you need to tell me is why using .stringof is bad. You have simply conjured up a rule and are stating it but not giving any reason why it is not a good idea to follow when, in fact, not following can be shown to be beneficial.
>>
>> You can't expect to lead by authority. Give a good reason why I should avoid it and change my current ways and I will.
>
> I have a couple times times now.
>
> https://forum.dlang.org/post/nvpsrxxkfmbbxognjsit@forum.dlang.org
>
> https://forum.dlang.org/post/fahrmmocegtthztzgkaa@forum.dlang.org
>
> I go into a lot of detail in the link on the second link.
>
> And the pains you are personally experiencing are a direct result of stringof. If you were to actually following my rule, you'd learn by doing how much better it is.
>
That is blatantly wrong. The code works EXACTLY the same way with and without using stringof.

You have not stated one type the reason why T string of is bad, you have just stated that it is bad, that is totally different.

I have removed all T.stringof's in the code and I still get the exact same errors. Your assessment that all the errors are due to T.stringof is wrong.

You need to provide code where using T directly works but T.stringof fails.

I did a search and replace for all the T.stringof's and the code produced the exact same output, so to say that is the source of all my problems is BS, and since I have already fixed most of the problems(the main ones of inout and protection still exist) after that, it shows that it had nothing to do with it.

I'm not saying it is a good idea, what I'm saying is that you haven't yet given any proof why it is a bad idea. Those links are you just stating it is bad.

If you want this not to be a waste of both of our times, next time post an example code that demonstrates the problem.


>
>> So it seems like the same design flaw exists? Have any work arounds for that?
>
> It won't work for private, you can use static if __traits(compiles) as a filter to get rid of them.

That doesn't help. It is compile time, one should be able to get the information. It is pointless to exclude it at CT because one could just open the source if there was anything to "hide". Protection is a runtime thing(except for CTFE).


April 08, 2019
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.

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

> 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!

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

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.

(interestingly, .tupleof does let you bypass privacy protections, but only for aggregate members, not for methods.)
April 08, 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.
}







April 08, 2019
On 4/8/2019 7:39 AM, Alex wrote:
> My point is that you are going ape shit over using T.stringof, you posted no 

> I mean, half the shit in __traits looks like it could be in std.traits and there 

Please tone down both the aggressiveness and the use of cuss words, and use professional demeanor.
April 08, 2019
On Saturday, 6 April 2019 at 12:20:28 UTC, Alex wrote:
>  Error: variable `std.traits.ParameterDefaults!(foo).Get!1u.Get` only parameters or stack based variables can be `inout`

so i think that is a bug in the phobos library

see: https://forum.dlang.org/thread/qbqvkcoexxtlvlxobzxn@forum.dlang.org
April 09, 2019
On Monday, 8 April 2019 at 21:52:59 UTC, Adam D. Ruppe wrote:
> On Saturday, 6 April 2019 at 12:20:28 UTC, Alex wrote:
>>  Error: variable `std.traits.ParameterDefaults!(foo).Get!1u.Get` only parameters or stack based variables can be `inout`
>
> so i think that is a bug in the phobos library
>
> see: https://forum.dlang.org/thread/qbqvkcoexxtlvlxobzxn@forum.dlang.org


I appreciate you looking in to it instead of writing it off. It basically proves my point that there are issues with D. These issues tend too be subtle and creep in to code and then that causes problems. I have been thrown off several times and when things don't work out I assume it is my code and when it's not I've already trashed my code trying to figure out what was wrong with it. These are the real problems with D and they come from two things: Not having a uniform and direct interface for reflection. Not having proper unit testing done for traits.

D is so heavy in meta programming that maybe it is time for a proper solution?
April 09, 2019
On Tuesday, 9 April 2019 at 14:42:38 UTC, Alex wrote:
> It basically proves my point that there are issues with D.

The language is fine in this case, it is a bug in the library.

Though, I don't think the library can be fixed because the language doesn't have facilities to express these things through libraries.... but I also don't see the point in having a library at all. You incur compile time and run time costs for stuff you probably don't need and introduce another layer of bugs.

Some of the lower level features are a little weird to see*, but they are easy to use once you get to know them.

* for example
   static if(is(typeof(overload) Params == __parameters))

to get the function parameter list (as the Params variable there). It is a little weird looking, but it isn't really hard to use.
April 09, 2019
On Tuesday, 9 April 2019 at 14:59:03 UTC, Adam D. Ruppe wrote:
> On Tuesday, 9 April 2019 at 14:42:38 UTC, Alex wrote:
>> It basically proves my point that there are issues with D.
>
> The language is fine in this case, it is a bug in the library.
>
I didn't say the language. The point with the language is that it could have built in semantics to do reflection in a inform way(__traits is somewhat uniform but messy and then one has std.traits which then makes it not uniform).

> Though, I don't think the library can be fixed because the language doesn't have facilities to express these things through libraries.... but I also don't see the point in having a library at all. You incur compile time and run time costs for stuff you probably don't need and introduce another layer of bugs.

There is no runtime costs. The library may not be efficient but it is a better design. It abstracts most of the crap away and provides a very natural and uniform interface in to reflection.

Ultimately the compiler itself should provide this information directly. It has all the information when it compiles and it can lazily instantiate whatever information it has to calculate when it is requested. It could be very efficient, it is just doing what __traits does but more naturally.

Reflection should be a first class semantic in D given D's heavy meta programming capabilities.



> Some of the lower level features are a little weird to see*, but they are easy to use once you get to know them.
>
> * for example
>    static if(is(typeof(overload) Params == __parameters))
>
> to get the function parameter list (as the Params variable there). It is a little weird looking, but it isn't really hard to use.


The problem is that there is a semantic that supposedly exists to dot he same but fails. So it is not about weirdness but about non-uniformity. Why does it have to be that way? There is no reason, it is also a hack in the compiler. WHy not just wrap that code with something sane like

Type.Reflect!Parameters

?

This is exactly what my library does and it is a more sane looking solution. It's that simple. You can't disagree, you know it looks better(we could argue about the precise syntax but it is much better and more informative than what you posted).

Also, your snippet is meant to be used, later on, such as in a for each loop,

when we could do

static foreach(p; Type.Reflect!Parameters)

vs

static if(is(typeof(overload) Params == __parameters))
    static foreach(p; Params)


It's 50% savings in both line space and character space, it's much faster to understand, it is uniform and natural while the second case is ugly, confusing, and bloated.


My point is that THERE IS NO NEED for such things. It is ALL about syntax. It's just wrappers. There is no new functionality. I'm just trying to make things "look" better because things that "look" better are easier to comprehend. Look better means that they are more uniform with common practices and experiences and allow for easier navigation in memory space.

You may be ok with having to remember special cases here and their... but it is a defect.  Suppose you program in 10 languages regularly, those special cases then are an order of magnitude more to remember... suppose you do other things with your life. If you don't and all you do is program D then you don't feel it as bad, if you do lots of other things then these are speed bumps that slows one down for no good reason at all(if you have one, besides, "some one has to code the new syntax and it takes work to make it better" then I'd like to hear it).

What I see if you justifying bad syntax just to justify it because it exists. If I'm wrong you just have to give me meaningful reasons why that is not the case.

I'm not looking to be confrontational, I'm looking to make things better. If you are right about what you claim then you can back it up, if not you can't except with fallacious arguments. My mind is willing to be changed as long as the change is provably good, else there is no point in going backwards.


I think the only argument you have is "It already exists and works and is not too bad"... which may be a good enough argument for you but isn't for me. That type of argument can be used to prevent progress on anything. "The cave is already exists and works to keep us sheltered and is not that bad so we don't need to build a nice house with AC that takes work to do". If all you have ever lived in is a cave then you can't possibly know if the house is better. It has to be built first to compare and contrast. The secret is that there is always something better than something else and it always should be sought after, at least theoretically(sure there is the practical issue of time, I accept that, but I don't accept denial that their isn't something better).


Hell, as much time that we have spent arguing over this shit we could have probably created a language feature that we both can agree is much better and is fast and really has no cons compared to what exists now.



April 09, 2019
On Tuesday, 9 April 2019 at 16:30:53 UTC, Alex wrote:
> On Tuesday, 9 April 2019 at 14:59:03 UTC, Adam D. Ruppe wrote:
>>[...]
> I didn't say the language. The point with the language is that it could have built in semantics to do reflection in a inform way(__traits is somewhat uniform but messy and then one has std.traits which then makes it not uniform).
>
> [...]

Have you considered writing a DIP?
April 09, 2019
On Tue, Apr 09, 2019 at 06:33:21PM +0000, Seb via Digitalmars-d-learn wrote:
> On Tuesday, 9 April 2019 at 16:30:53 UTC, Alex wrote:
> > On Tuesday, 9 April 2019 at 14:59:03 UTC, Adam D. Ruppe wrote:
> > > [...]
> > I didn't say the language. The point with the language is that it could have built in semantics to do reflection in a inform way(__traits is somewhat uniform but messy and then one has std.traits which then makes it not uniform).
> > 
> > [...]
> 
> Have you considered writing a DIP?

I think the original intent was that __traits was supposed to be low-level, implementation-specific calls into the compiler, while std.traits is supposed to be the user-friendly syntactic sugar built on top that user code is supposed to use.

Unfortunately, it turned out that people prefer using __traits directly instead, and std.traits hasn't quite been keeping up with new __traits (e.g., AFAIK __traits(compiles) does not have a std.traits equivalent), and is also less familiar to many people, so now we have a mishmash of code sometimes using __traits and sometimes std.traits.


T

-- VI = Visual Irritation