www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Overloads not returning appropriate info. [Field reflunkory]

reply Alex <AJ gmail.com> writes:
Trying to get parameter info of an overloaded method, it doesn't 
return the names. The same code works fine for a free function.


	Id = foo
	TypeName =
	FullName = main.foo
	ModuleName = main
	MangledName = _D4main3fooFiKdfZv
	Protection = public
	Body =
	Uses = []
	Attributes = [
		sAttributeReflection("attr!string(\"test\", 432)", 
"attr!string"),
		sAttributeReflection("4", "int")
	]
	DType = function
	Signature = void(int x, ref double y, float z = 43234.3F)
	NumArgs = 3
	Linkage = D
	ReturnType = void
	Parameters = [
		sParameterReflection("x", "int", "void", "void", 
sStorageClass(false, false, false, false, false, false)),
		sParameterReflection("y", "double", "void", "void", 
sStorageClass(false, false, false, true, false, false)),
		sParameterReflection("z", "float", "43234.3F", "float", 
sStorageClass(false, false, false, false, false, false))
	]



vs





	Methods = [
		Id = foo
		TypeName = int()
		FullName = mModel.cDerived!(int).foo
		ModuleName = mModel
		MangledName = 6mModel__T8cDerivedTiZQm3foo
		Protection = public
		Body =
		Uses = []
		Attributes = [sAttributeReflection("A", "string")]
		Signature = int()
		NumArgs = 0
		Linkage = D
		ReturnType = int
		Parameters = []
		DType = delegate
		Overloads = []
		,
		Id = foo
		TypeName = pure nothrow  nogc  safe int(int, inout(float))
		FullName = mModel.cDerived!(int).foo
		ModuleName = mModel
		MangledName = 6mModel__T8cDerivedTiZQm3foo
		Protection = public
		Body =
		Uses = []
		Attributes = [sAttributeReflection("A", "string")]
		Signature = pure nothrow  nogc  safe int(int, inout(float))
		NumArgs = 2
		Linkage = D
		ReturnType = int
		Parameters = [
			sParameterReflection("", "int", "void", "void", 
sStorageClass(false, false, false, false, false, false)),
			sParameterReflection("", "inout(float)", "void", "void", 
sStorageClass(false, false, false, false, false, false))
		]
		DType = delegate
		Overloads = []
		,




sParameterReflection("z", "float", "43234.3F", "float", 
sStorageClass(false, false, false, false, false, false))

vs

sParameterReflection("", "int", "void", "void", 
sStorageClass(false, false, false, false, false, false)),

notice that some info is field out but not all.

The code is here:
https://github.com/IncipientDesigns/Dlang_Reflect/blob/master/mReflect.d

The Base, Aggregate, Function, and Method classes are the 
appropriate ones to look at. cFunctionReflection does all the 
work though

[Field reflunkory]

Also, with

cFieldReflection I cannot pass the field as a type on to the base 
class to reduce code duplication. Ideally I should be able to 
pass a field around as a type so that reflection can occur on it. 
This seems like a language design issue but maybe there is a 
trick?
Apr 04 2019
next sibling parent reply Alex <AJ gmail.com> writes:
No one has a clue about this?
Apr 05 2019
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 5 April 2019 at 14:38:21 UTC, Alex wrote:
 No one has a clue about this?
Your code has a lot of layers to unfold, but instead let me just show you a working example and then maybe you can fix your own code: --- class A { void foo(int a) {} void foo(int b, int c) {} } void main() { import std.stdio; foreach(overload; __traits(getOverloads, A, "foo")) { writeln(typeof(overload).stringof); static if(is(typeof(overload) Params == __parameters)) static foreach(idx, _; Params) {{ alias param = Params[idx .. idx + 1]; writeln("\t", __traits(identifier, param)); }} } } --- I don't know if your bug is in your code or in std.traits or what, but this example works and prints out void(int a) a void(int b, int c) b c The one bizarre thing is the `param = Params[idx .. idx + 1]` bit. I wrote a little about this for parameter attributes too http://dpldocs.info/this-week-in-d/Blog.Posted_2019_02_11.html#how-to-get-uda-on-a-function-param but it also applies to getting the identifier out.
Apr 05 2019
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
BTW `T.stringof` is usually a bug waiting to happen. You are 
using mixin in a lot of places where you shouldn't be and this is 
going to lead to name conflicts, import problems, and more. Just 
use `T`.

If you need a member, use __traits(getMember, T, "name").
Apr 05 2019
parent reply Alex <AJ gmail.com> writes:
On Friday, 5 April 2019 at 15:38:18 UTC, Adam D. Ruppe wrote:
 BTW `T.stringof` is usually a bug waiting to happen. You are 
 using mixin in a lot of places where you shouldn't be and this 
 is going to lead to name conflicts, import problems, and more. 
 Just use `T`.

 If you need a member, use __traits(getMember, T, "name").
I fixed the parameter info issue and rewrote a large portion of the code to work better, the main problem was that I was doing static foreach (f; typeof(__traits(getOverloads, T, m))) but now I get Error: variable `std.traits.ParameterDefaults!(foo).Get!1u.Get` only parameters or stack based variables can be `inout` sParameterReflection("y", "inout(float)", "void", "void", sStorageClass(false, false, false, false, false, false)), for pure nothrow nogc safe int(int x, inout(float) y = 4.00000F, double x7 = 434.3) inout clearly has a default value but an error is given. All other default values are returning correctly. static if (__traits(compiles, typeof(ParameterDefaults!T[k]))) { enum pd = ParameterDefaults!T[k]; alias dt = typeof(pd); } else { alias dt = void; alias pd = void; } t.Parameters ~= sParameterReflection(ParameterIdentifierTuple!T[k], a.stringof, pd.stringof, dt.stringof); Without the __traits compiles the error occurs in the enum by simply taking ParameterDefaults. --------------------------------------------------- The mixin code with T are to build compound names. I never use a mixin for just accessing T alone as far as I know, you are going to have to be more clear on what you are talking about here. probably 90% of the mixins are of the form mixin(`Protection = __traits(getProtection, (`~T.stringof~`).`~name~`);`); Where I have to build the type info, such things as Protection = __traits(getProtection, T.name); will definitely not work. ------------------------- This is now the output of the code and everything seems to basically work now except the above issue. Id = cDerived TypeName = cDerived!int FullName = mModel.cDerived!(int) ModuleName = mModel MangledName = C6mModel__T8cDerivedTiZQm Protection = public Body = Uses = [] Attributes = [ sAttributeReflection("fdsa", "string"), sAttributeReflection("8", "int") ] IsNested = false IsInnerClass = false HasUnsharedAliasing = true HasNested = false HasIndirections = true HasElaborateDestructor = false HasElaborateCopyConstructor = false HasElaborateAssign = false HasAliasing = true TypeParameters = [] AliasThis = [sTypeReflection("type", "cType")] NestedAggregates = [] DerivedClasses = [] Fields = [ Id = type TypeName = cDerived!int.type FullName = mModel.cDerived!(int).type ModuleName = mModel MangledName = C6mModel__T8cDerivedTiZQm Protection = public Body = Uses = [] Attributes = [] DType = field , Id = testField1 TypeName = cDerived!int.testField1 FullName = mModel.cDerived!(int).testField1 ModuleName = mModel MangledName = C6mModel__T8cDerivedTiZQm Protection = public Body = Uses = [] Attributes = [sAttributeReflection("XXXRRERES", "string")] DType = field , Id = testField2 TypeName = cDerived!int.testField2 FullName = mModel.cDerived!(int).testField2 ModuleName = mModel MangledName = C6mModel__T8cDerivedTiZQm Protection = private Body = Uses = [] Attributes = [sAttributeReflection("XXXRRERES4", "string")] DType = field ] Methods = [ Id = foo TypeName = FullName = mModel.cDerived!(int).foo ModuleName = mModel MangledName = _D6mModel__T8cDerivedTiZQm3fooMFZi Protection = public Body = Uses = [] Attributes = [sAttributeReflection("A", "string")] Signature = int() NumArgs = 0 Linkage = D ReturnType = int Parameters = [] Overloads = [ Id = foo TypeName = FullName = mModel.cDerived!(int).foo ModuleName = mModel MangledName = _D6mModel__T8cDerivedTiZQm3fooMFNaNbNiNfiNgfdZi Protection = private Body = Uses = [] Attributes = [sAttributeReflection("B", "string")] DType = function Signature = pure nothrow nogc safe int(int x, inout(float) y = 4.00000F, double x7 = 434.3) NumArgs = 3 Linkage = D ReturnType = int Parameters = [ sParameterReflection("x", "int", "void", "void", sStorageClass(false, false, false, false, false, false)), sParameterReflection("y", "inout(float)", "void", "void", sStorageClass(false, false, false, false, false, false)), sParameterReflection("x7", "double", "void", "void", sStorageClass(false, false, false, false, false, false)) ] , Id = foo TypeName = FullName = mModel.cDerived!(int).foo ModuleName = mModel MangledName = _D6mModel__T8cDerivedTiZQm3fooMFiKdlfZi Protection = public Body = Uses = [] Attributes = [ sAttributeReflection("attr!string(\"test\", 432)", "attr!string"), sAttributeReflection("4", "int") ] DType = function Signature = int(int x, ref double y, long q = 3L, float z = 43234.3F) NumArgs = 4 Linkage = D ReturnType = int Parameters = [ sParameterReflection("x", "int", "void", "void", sStorageClass(false, false, false, false, false, false)), sParameterReflection("y", "double", "void", "void", sStorageClass(false, false, false, true, false, false)), sParameterReflection("q", "long", "3L", "long", sStorageClass(false, false, false, false, false, false)), sParameterReflection("z", "float", "43234.3F", "float", sStorageClass(false, false, false, false, false, false)) ] ] DType = delegate , Id = foo TypeName = FullName = mModel.cDerived!(int).foo ModuleName = mModel MangledName = _D6mModel__T8cDerivedTiZQm3fooMFZi Protection = public Body = Uses = [] Attributes = [sAttributeReflection("A", "string")] Signature = int() NumArgs = 0 Linkage = D ReturnType = int Parameters = [] Overloads = [ Id = foo TypeName = FullName = mModel.cDerived!(int).foo ModuleName = mModel MangledName = _D6mModel__T8cDerivedTiZQm3fooMFNaNbNiNfiNgfdZi Protection = private Body = Uses = [] Attributes = [sAttributeReflection("B", "string")] DType = function Signature = pure nothrow nogc safe int(int x, inout(float) y = 4.00000F, double x7 = 434.3) NumArgs = 3 Linkage = D ReturnType = int Parameters = [ sParameterReflection("x", "int", "void", "void", sStorageClass(false, false, false, false, false, false)), sParameterReflection("y", "inout(float)", "void", "void", sStorageClass(false, false, false, false, false, false)), sParameterReflection("x7", "double", "void", "void", sStorageClass(false, false, false, false, false, false)) ] , Id = foo TypeName = FullName = mModel.cDerived!(int).foo ModuleName = mModel MangledName = _D6mModel__T8cDerivedTiZQm3fooMFiKdlfZi Protection = public Body = Uses = [] Attributes = [ sAttributeReflection("attr!string(\"test\", 432)", "attr!string"), sAttributeReflection("4", "int") ] DType = function Signature = int(int x, ref double y, long q = 3L, float z = 43234.3F) NumArgs = 4 Linkage = D ReturnType = int Parameters = [ sParameterReflection("x", "int", "void", "void", sStorageClass(false, false, false, false, false, false)), sParameterReflection("y", "double", "void", "void", sStorageClass(false, false, false, true, false, false)), sParameterReflection("q", "long", "3L", "long", sStorageClass(false, false, false, false, false, false)), sParameterReflection("z", "float", "43234.3F", "float", sStorageClass(false, false, false, false, false, false)) ] ] DType = delegate , Id = ValueProp TypeName = FullName = mModel.cDerived!(int).ValueProp ModuleName = mModel MangledName = _D6mModel__T8cDerivedTiZQm9ValuePropMFNdZi Protection = public Body = Uses = [] Attributes = [sAttributeReflection("VP att", "string")] Signature = property int() NumArgs = 0 Linkage = D ReturnType = int Parameters = [] Overloads = [] DType = delegate ] InheritedInterfaces = [ Id = iX TypeName = iX FullName = mModel.iX ModuleName = mModel MangledName = C6mModel2iX Protection = public Body = Uses = [] Attributes = [] IsNested = false IsInnerClass = false HasUnsharedAliasing = true HasNested = false HasIndirections = true HasElaborateDestructor = false HasElaborateCopyConstructor = false HasElaborateAssign = false HasAliasing = true TypeParameters = [] AliasThis = [] NestedAggregates = [] DerivedClasses = [] Fields = [ Id = TypeName = FullName = ModuleName = MangledName = Protection = Body = Uses = [] Attributes = [] DType = field ] Methods = [] DType = interface InheritedInterfaces = [] , Id = iY TypeName = iY FullName = mModel.iY ModuleName = mModel MangledName = C6mModel2iY Protection = public Body = Uses = [] Attributes = [] IsNested = false IsInnerClass = false HasUnsharedAliasing = true HasNested = false HasIndirections = true HasElaborateDestructor = false HasElaborateCopyConstructor = false HasElaborateAssign = false HasAliasing = true TypeParameters = [] AliasThis = [] NestedAggregates = [] DerivedClasses = [] Fields = [ Id = TypeName = FullName = ModuleName = MangledName = Protection = Body = Uses = [] Attributes = [] DType = field ] Methods = [] DType = interface InheritedInterfaces = [] ] DType = class IsAbstract = false Alignment = 8 InheritedClasses = [ Id = cBase TypeName = cBase FullName = mModel.cBase ModuleName = mModel MangledName = C6mModel5cBase Protection = public Body = Uses = [] Attributes = [] IsNested = false IsInnerClass = false HasUnsharedAliasing = true HasNested = false HasIndirections = true HasElaborateDestructor = false HasElaborateCopyConstructor = false HasElaborateAssign = false HasAliasing = true TypeParameters = [] AliasThis = [] NestedAggregates = [] DerivedClasses = [] Fields = [ Id = testField TypeName = cBase.testField FullName = mModel.cBase.testField ModuleName = mModel MangledName = C6mModel5cBase Protection = public Body = Uses = [] Attributes = [] DType = field ] Methods = [ Id = fooBase TypeName = FullName = mModel.cBase.fooBase ModuleName = mModel MangledName = _D6mModel5cBase7fooBaseMFCQy5iBaseZCQBiQBe Protection = public Body = Uses = [] Attributes = [] Signature = cBase(iBase c) NumArgs = 1 Linkage = D ReturnType = cBase Parameters = [ sParameterReflection("c", "iBase", "void", "void", sStorageClass(false, false, false, false, false, false)) ] Overloads = [] DType = delegate ] InheritedInterfaces = [ Id = iBase TypeName = iBase FullName = mModel.iBase ModuleName = mModel MangledName = C6mModel5iBase Protection = public Body = Uses = [] Attributes = [ sAttributeReflection("fdsa", "string"), sAttributeReflection("4", "int") ] IsNested = false IsInnerClass = false HasUnsharedAliasing = true HasNested = false HasIndirections = true HasElaborateDestructor = false HasElaborateCopyConstructor = false HasElaborateAssign = false HasAliasing = true TypeParameters = [] AliasThis = [] NestedAggregates = [] DerivedClasses = [] Fields = [ Id = TypeName = FullName = ModuleName = MangledName = Protection = Body = Uses = [] Attributes = [] DType = field ] Methods = [ Id = fooBase TypeName = FullName = mModel.iBase.fooBase ModuleName = mModel MangledName = _D6mModel5iBase7fooBaseMFCQyQtZQg Protection = public Body = Uses = [] Attributes = [] Signature = iBase(iBase) NumArgs = 1 Linkage = D ReturnType = iBase Parameters = [ sParameterReflection("", "iBase", "void", "void", sStorageClass(false, false, false, false, false, false)) ] Overloads = [] DType = delegate ] DType = interface InheritedInterfaces = [] ] DType = class IsAbstract = false Alignment = 4 InheritedClasses = [Object] ] Id = bar TypeName = FullName = mMain.bar ModuleName = mMain MangledName = _D5mMain3barFiKdfZv Protection = public Body = Uses = [] Attributes = [ sAttributeReflection("attr!string(\"test\", 432)", "attr!string"), sAttributeReflection("4", "int") ] DType = function Signature = void(int x, ref double y, float z = 43234.3F) NumArgs = 3 Linkage = D ReturnType = void Parameters = [ sParameterReflection("x", "int", "void", "void", sStorageClass(false, false, false, false, false, false)), sParameterReflection("y", "double", "void", "void", sStorageClass(false, false, false, true, false, false)), sParameterReflection("z", "float", "43234.3F", "float", sStorageClass(false, false, false, false, false, false)) ] Overloads = [ Id = bar TypeName = FullName = mMain.bar ModuleName = mMain MangledName = _D5mMain3barFiKdlfZv Protection = public Body = Uses = [] Attributes = [sAttributeReflection("564", "int")] DType = function Signature = void(int x, ref double y, long q = 3L, float z = 43234.3F) NumArgs = 4 Linkage = D ReturnType = void Parameters = [ sParameterReflection("x", "int", "void", "void", sStorageClass(false, false, false, false, false, false)), sParameterReflection("y", "double", "void", "void", sStorageClass(false, false, false, true, false, false)), sParameterReflection("q", "long", "3L", "long", sStorageClass(false, false, false, false, false, false)), sParameterReflection("z", "float", "43234.3F", "float", sStorageClass(false, false, false, false, false, false)) ] ]
Apr 06 2019
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 6 April 2019 at 12:20:28 UTC, Alex wrote:
 static foreach (f; typeof(__traits(getOverloads, T, m)))
Why are you using typeof here?
 probably 90% of the mixins are of the form

 mixin(`Protection = __traits(getProtection, 
 (`~T.stringof~`).`~name~`);`);
Try following this rule: NEVER use .stringof.
 Protection = __traits(getProtection, T.name);
But (unless T.name is private; this is a design flaw in __traits(getProtection)), __traits(getProtection, __traits(getMember, T, name)) will work.
Apr 06 2019
parent reply Alex <AJ gmail.com> writes:
On Saturday, 6 April 2019 at 13:03:31 UTC, Adam D. Ruppe wrote:
 On Saturday, 6 April 2019 at 12:20:28 UTC, Alex wrote:
 static foreach (f; typeof(__traits(getOverloads, T, m)))
Why are you using typeof here?
I don't know, I want to say I copied that code from somewhere but it might have been a left over or when I was trying to get the code to work. Since it partially worked(notice that it "works" and only gives the errors in parameters).
 probably 90% of the mixins are of the form

 mixin(`Protection = __traits(getProtection, 
 (`~T.stringof~`).`~name~`);`);
Try following this rule: NEVER use .stringof.
rules are meant to be broken. As I mentioned in the other post it doesn't help when writing the mixin as a pragma to inform one of the actual type being used. I'd say the rule is actually crap because of this(if debugging mixins and meta code had more support it might be a good rule but it's very helpful to know the type. Sure we can add a pragma(msg, T) but sometimes I just replace mixin( with pragma(msg, and I want something more than it display T. I want to see the full string to make sure it is formatted correctly what what is being used for T. 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. Just telling me to do it won't change my mind. The only reason I can see why it is a good rule is that one doesn't have to use T.stringof when they can just use T directly, making the code a little easier to read. But I've pointed out that T.stringof has it's use when viewing the mixin as a string, which overrides your rule if the only reason is it's not technically needed. See, it might just be your own bias that makes you not like it when in reality it might not matter either way. So far it seems it is your bias but I hope you have a good objective reason why as it would same a few characters in typing. A good reason is "It breaks the compiler in these cases" or "It causes this problem here when you do this". If it's just about code readability then I will keep using them and maybe when I get the code in to shape I will try to format it to take them out. But in that case you have to learn to accept them in prototyping because then they are useful for mixin->pragma(msg,
 Protection = __traits(getProtection, T.name);
But (unless T.name is private; this is a design flaw in __traits(getProtection)), __traits(getProtection, __traits(getMember, T, name)) will work.
Ok, so I used it and it got rid of one error where I get the protection. I still get a protection issue for a private field using this code though: mixin(`static foreach(a; __traits(getAttributes, T.`~name~`)) Attributes ~= sAttributeReflection(to!string(a), typeof(a).stringof);`); So it seems like the same design flaw exists? Have any work arounds for that? Thanks for your help!
Apr 06 2019
next sibling parent Paul Backus <snarwin gmail.com> writes:
On 4/6/19 11:47 PM, 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.
I'm not Adam, but I've also run into problems with .stringof, and have found avoiding it to be a good idea in a lot of situations. The problem with .stringof and string mixins is that types and symbols carry information about their context with them--what module they're from, what scope they're defined in, etc. This is why, for example, you can pass a type defined in module a to a template defined in module b and have it work without needed to add `import a` to module b. When you convert a type or symbol to a string using .stringof, all of this context information is stripped away. And in many cases, once that information has been lost, it's impossible to recover. For example, if all you have is the string "S", and two modules in your program define a `struct S`, there's no way to know which one of those types your string refers to. If you say, "fine, I'll just use fully-qualified names," well, that doesn't work either, because some types in D don't *have* externally-visible names [1]. If you convert a type like that to a string, you can never get the original type (with its context info) back, no matter what you do. All that said, it's perfectly fine to use .stringof for debugging and custom error messages. But if you're using it to generate code, you are almost certainly making a mistake. [1] https://wiki.dlang.org/Voldemort_types
Apr 07 2019
prev sibling next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
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.
 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.
Apr 07 2019
parent reply Alex <AJ gmail.com> writes:
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).
Apr 07 2019
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
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.)
Apr 08 2019
parent reply Alex <AJ gmail.com> writes:
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. }
Apr 08 2019
parent Walter Bright <newshound2 digitalmars.com> writes:
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.
Apr 08 2019
prev sibling parent FeepingCreature <feepingcreature gmail.com> writes:
On Sunday, 7 April 2019 at 03:47:25 UTC, Alex wrote:
 rules are meant to be broken.
No they're not! Almost by definition not! More comprehensively, if you break a rule you take responsibility for the outcome. You wanna use stringof? "Don't use stringof for that." "rules are meant to be broken." -- "Wah, my code doesn't work, stringof is shit, bad design, fix D pls." Don't ask questions if you don't care about the answers. More importantly, don't ignore advice and then complain about it.
 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.
Your code will break in surprising and unfixable ways. `stringof` is not *for* mixin. If you use it for mixin, you will be on your own design-wise. The language will not be changed to "fix" the "bugs" you run into. It will work until it won't work, and then you'll have to rewrite the entire thing anyway. Don't use stringof for mixin.
Apr 07 2019
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
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
Apr 08 2019
parent reply Alex <AJ gmail.com> writes:
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?
Apr 09 2019
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
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.
Apr 09 2019
parent reply Alex <AJ gmail.com> writes:
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.
Apr 09 2019
parent reply Seb <seb wilzba.ch> writes:
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?
Apr 09 2019
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
Apr 09 2019
parent reply Alex <AJ gmail.com> writes:
On Tuesday, 9 April 2019 at 18:56:58 UTC, H. S. Teoh wrote:
 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.
That may be the case but I recently saw some one here say "All the roads to hell are paved with good intentions", which isn't hyperbole. The better the initial plan the better things will turn out. Planning is the key to success, without it there is only luck. My point has been and is that there is a better way that is more natural. I make no claims about anything else. It may be a cop out to say something that is a tautology but I make the claim as an emphasis that I believe that it is more true in this case than others. i.e., D's traits are PITA. Ok, they are not as bad as some things but I know they can be better since I have used other D. Because D has such an extensive meta programming language(the best I've seen for procedural) it needs a well thought out and natural reflection scheme. traits works but the more I use it the more I believe it could have been done better. It's one thing to use it here and there, but when you use it everywhere the issues multiply. I think the library I through together at least demonstrates a much more natural way(and it was just a first attempt without any planning). I imagine something much better could be created with some proper planning and teamwork. My impression though is few people here actually care about such things.
Apr 09 2019
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Apr 09, 2019 at 08:49:17PM +0000, Alex via Digitalmars-d-learn wrote:
 On Tuesday, 9 April 2019 at 18:56:58 UTC, H. S. Teoh wrote:
[...]
 My point has been and is that there is a better way that is more
 natural.  I make no claims about anything else. It may be a cop out to
 say something that is a tautology but I make the claim as an emphasis
 that I believe that it is more true in this case than others. i.e.,
 D's traits are PITA. Ok, they are not as bad as some things but I know
 they can be better since I have used other languages that have far

As I said, __traits was never designed to be user-friendly, or even "logical". It was supposed to be a quick-and-easy way to tap into compiler internals, and std.traits was supposed to be the proper API to introspection. But std.traits, as it stands, is far, far from what it ought to be, and so we have today's sorry situation. (And on a side note: don't even get me started on is(...) expressions.) Anyway, since you seem to be passionate about this, this could be your chance of making std.traits what it ought to have been all along, or making a sensible reflection library that can for all practical purposes replace std.traits. I, for one thing, would appreciate a nicer API to introspection than what we currently have. One of the main things that drew me to D was its metaprogramming capabilities, and while overall it has been a positive experience, there *are* flies in the ointment like __traits, is(...) expressions, etc.. If you or somebody else could come up with a saner way to do introspection in D, it'd be very much appreciated. T -- Life would be easier if I had the source code. -- YHL
Apr 09 2019
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Tuesday, 9 April 2019 at 21:00:55 UTC, H. S. Teoh wrote:
 (And on a side note: don't even get me started on is(...) 
 expressions.)
is expressions rock. And I betcha if we did do libraries for them, it would eventually go full circle, with someone doing a pattern-matching DSL that reinvents the original syntax, just much slower to compile :P
Apr 09 2019
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Apr 10, 2019 at 02:22:35AM +0000, Adam D. Ruppe via Digitalmars-d-learn
wrote:
 On Tuesday, 9 April 2019 at 21:00:55 UTC, H. S. Teoh wrote:
 (And on a side note: don't even get me started on is(...)
 expressions.)
is expressions rock. And I betcha if we did do libraries for them, it would eventually go full circle, with someone doing a pattern-matching DSL that reinvents the original syntax, just much slower to compile :P
The functionality rocks, but the syntax is a horrendous hairball of inconsistencies and design-by-chance. T -- It's bad luck to be superstitious. -- YHL
Apr 10 2019
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 10 April 2019 at 10:18:35 UTC, H. S. Teoh wrote:
 The functionality rocks, but the syntax is a horrendous 
 hairball of inconsistencies and design-by-chance.
There's a little bit weird about it, but it makes sense. I used to find it hard to even remember how it works, but then I had to describe it for the book and it all came together. Consider this. Declaring a normal local variable: --- int foo = 0; --- We can generalize that to --- Type_Name Local_Name Operator Initial_Value --- Well, now, compare to the is expression: --- is(typeof(func) Params == __parameters) --- It is a bit of a stretch, but the general shape is the same. We can define the is expression generally to be: is(Type_Name Local_Name Deconstruction_Pattern) And then both Local_Name and Deconstruction_Pattern are optional. This gives us all the forms from the website https://dlang.org/spec/expression.html#IsExpression (from point 1: is(Type). This has the type, but left out the local name and deconstruction pattern. All it cares about is if the type exists. 2: is(Type : something). This deconstruction pattern, using :, means "can implicitly convert to something" The deconstruction pattern mimics common ways of writing such types; class A : B {} defines a type A that can implicitly cast to B, so is(A : B) would pass and return true. 3: is(Type == something). This deconstruction pattern, using ==, just needs an exact match. It is probably the easiest one for people to remember. 4: is(Type Identifier). This skips the deconstruction pattern, meaning it is the most basic "this type must exist" check, but includes the local name. Like with `int a;`, the name comes after the type. including the optional local name. optional local name. At this point, the documentation also includes other deconstruction patterns, like the `class` keyword, etc. These are mostly very simple, but it is slightly magical in places because it can initialize Identifier to other thing.. but is that really weird? int a = 10; The value of a is dependent on the right side, and so is the Identifier here. It looks totally wrong because it is using == here rather than =, so we intuitively think is(A B == C) is comparing B and C... but just rewrite in your brain that this is actually declaring a variable with a funky deconstruction initializer and it will make sense again. So the whole `== C` part is the deconstruction pattern, and B is the variable being set to it. And being a deconstruction pattern, it is trying to pull layers off, so stuff like is(MyClass Parents == super), the ==super pattern is deconstructing its super keyword; its base classes. Think of it not as comparison, but as matching a deconstruction pattern and it will make more sense. I know its weird, but we can work with it. Let's move on: 7: This one has a lot of examples, but it really just expands on the deconstruction pattern. For example: static if(is(int[10] == T[N], T, size_t N)) What's the pattern here? == means use exact comparison, not implicitly converting comparison. T[N] writes out a model of what the declaration is expected to look like. Then commas separate the definitions of each placeholder variable, just as if they were template argument definitions. Same syntax, different location. The one tricky thing is the compiler will not tell you when you malformed the pattern (for the most part), just nothing will happen to match it. So match it on some known quantity to test via static assert or something. To use a complex pattern with the optional name: static if(is(int[10] OriginalType == T[N], T, size_t N)) that's all the pieces together. Not so bad when you know how it breaks down.
Apr 10 2019
parent reply Alex <AJ gmail.com> writes:
On Wednesday, 10 April 2019 at 14:06:53 UTC, Adam D. Ruppe wrote:
 On Wednesday, 10 April 2019 at 10:18:35 UTC, H. S. Teoh wrote:
 [...]
There's a little bit weird about it, but it makes sense. I used to find it hard to even remember how it works, but then I had to describe it for the book and it all came together. Consider this. [...]
I wonder if there are some interesting patterns of nesting is's? is(...is(...is(...)...)...)
Apr 10 2019
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 10 April 2019 at 19:29:13 UTC, Alex wrote:
 I wonder if there are some interesting patterns of nesting is's?

 is(...is(...is(...)...)...)
No, at least not like that. You'd get nothing out of it, even if you made it work. But, I have in the past nested static ifs with different is things in order to handle very complex patterns that are difficult to express in one. I can't remember what those are right now though... but if one level fails, you might do static if(is( something )) static if(is( details )) { } to drill down. But while I know I have done this before, it is rare enough that I cannot recall it!
Apr 10 2019
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Apr 10, 2019 at 11:05:27PM +0000, Adam D. Ruppe via Digitalmars-d-learn
wrote:
 On Wednesday, 10 April 2019 at 19:29:13 UTC, Alex wrote:
 I wonder if there are some interesting patterns of nesting is's?
 
 is(...is(...is(...)...)...)
No, at least not like that. You'd get nothing out of it, even if you made it work. But, I have in the past nested static ifs with different is things in order to handle very complex patterns that are difficult to express in one. I can't remember what those are right now though... but if one level fails, you might do static if(is( something )) static if(is( details )) { } to drill down. But while I know I have done this before, it is rare enough that I cannot recall it!
It happens when your static if condition has two or more clauses, and the compilability of one of the later clauses depend on the truth of a previous clause. Static if conditions do respect && short-circuit evaluation, but they do not allow you to bypass compilability, so if you have something like: static if (A & B) { ... } where B is not compilable unless A is true, then you cannot write it this way, and have to nest it like you wrote above. T -- We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the Internet, we know this is not true. -- Robert Wilensk
Apr 10 2019
prev sibling parent Alex <AJ gmail.com> writes:
On Tuesday, 9 April 2019 at 21:00:55 UTC, H. S. Teoh wrote:
 On Tue, Apr 09, 2019 at 08:49:17PM +0000, Alex via 
 Digitalmars-d-learn wrote:
 On Tuesday, 9 April 2019 at 18:56:58 UTC, H. S. Teoh wrote:
[...]
 My point has been and is that there is a better way that is 
 more natural.  I make no claims about anything else. It may be 
 a cop out to say something that is a tautology but I make the 
 claim as an emphasis that I believe that it is more true in 
 this case than others. i.e., D's traits are PITA. Ok, they are 
 not as bad as some things but I know they can be better since 
 I have used other languages that have far more logical 

As I said, __traits was never designed to be user-friendly, or even "logical". It was supposed to be a quick-and-easy way to tap into compiler internals, and std.traits was supposed to be the proper API to introspection. But std.traits, as it stands, is far, far from what it ought to be, and so we have today's sorry situation.
That's unfortunate... but at least they are generally pretty functional. I remember trying to do basic type comparisons in later but I believe that was the time I left for D). I can understanding adding traits int he way it was, but at some point it has to be brought to the same standard as the rest of the language. It's just far too important to neglect. After all, Even most of phobos is using meta programming.
 (And on a side note: don't even get me started on is(...) 
 expressions.)

 Anyway, since you seem to be passionate about this, this could 
 be your chance of making std.traits what it ought to have been 
 all along, or making a sensible reflection library that can for 
 all practical purposes replace std.traits.
The problem is, I believe to do it right, it should be done in the compiler(at least some changes) and I know virtually nothing about the design and internals, so it would be much more time consuming than I'd like). I feel if I were going to go down that route I'd rather spend time writing a compiler or getting better as functional programming.
 I, for one thing, would appreciate a nicer API to introspection 
 than what we currently have.  One of the main things that drew 
 me to D was its metaprogramming capabilities, and while overall 
 it has been a positive experience, there *are* flies in the 
 ointment like __traits, is(...) expressions, etc..  If you or 
 somebody else could come up with a saner way to do 
 introspection in D, it'd be very much appreciated.
Basically same here. D is one of those love/hate relationships ;/ Meta programming is the next stage of evolution of programming. It is necessary for simplifying the complex problems of the modern computing world. D does have quite a nice syntax for most of this and does reasonably well(Although I believe functional programming blows D's type system out the water since it deals with structural mapping directly without "special cases").
Apr 10 2019
prev sibling parent reply Alex <AJ gmail.com> writes:
On Tuesday, 9 April 2019 at 18:33:21 UTC, Seb 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?
No, because I expect it won't even be considered. The typical responses I have seen to this sort of thing is that "we already have it". Hence why I decided to write my own lib, and then had a few issues. Andre did look in to some of the ideas and said he would pass it off to some GSOC students to look in to making it better, so maybe something will come out of that. I believe that basically the compiler simply needs to present a better interface in to reflection. This should have been done from the get go but I guess __traits has been patched together over time as as things were needed. Essentially the compiler would need to do what I have done and wrap __traits and std.traits in to a more uniform interface. It would add an extra layer of indirection though since the wrapper needs then to stay consistent with any traits changes. My library works well but is incomplete and has some bugs to due bugs in traits. It is, though, rather slow and I haven't worked on fixing it. (actually it doesn't seem to add too much overhead after the first call but I imagine that is due to the template being instantiated already in the module, might multiply for each new module it is used in) What I'm thinking is that maybe it is better to have some range like semantics used for reflection. I have thought about it much but I got the idea earlier. Type.Reflect.Accessor.Accessor.Selector.Selector.Accessor... The idea is that one can access stuff from the type and then use certain keywords to select and filter and then access more. I say it is range like but I'm not sure if ranges would work or not or if it would just be dispatching. E.g., MyClass.Reflect.TemplateParameters.Select!int.Names Would get the template parameters of MyClass, then select only those with int and then get the names of those parameters. (this could work in general for runtime too) MyClass.SomeArray.Select("x.value == 4").name; which is why I say it is sorta like ranges(which I'm thinking more of piping). I just haven't thought about it much and there doesn't seem to be much interest in going this route... I think it would be a great addition to D but others seem to not care or are more interested in arguing to relatively insignificant issues.
Apr 09 2019
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Tuesday, 9 April 2019 at 20:45:18 UTC, Alex wrote:
 On Tuesday, 9 April 2019 at 18:33:21 UTC, Seb wrote:
 Have you considered writing a DIP?
No, because I expect it won't even be considered.
You won't pass review if you don't show knowledge of the existing language, but there's a lot of people who are interested in a few changes. A few years ago, there was a proposal for a magical `meta` namespace that would call into the compiler for syntax sugar on CT reflection. The old idea was to replace `__traits(X, args)` with `meta.X(args)` - pure syntax change - but you could perhaps revive and expand that as the entry point to your new idea and get some people on board. I'm skeptical of any reflection library, but compiler changes might be able to change that. The status quo for D's reflection libraries are: 1) weird bugs and/or omissions since the language does not let you express all the function parameter details as return values or local variables. 2) slow compile times (you said your thing was 10 seconds! that's utterly unacceptable) 3) not actually significantly easier to use than language built-ins (if they are actually easier to use at all!) So any library without compiler changes is, as of today, I believe *impossible* to get right, and getting as close as you can is horribly slow. So, your DIP would necessarily include language+compiler changes. And the compiler is *already* (almost) fully capable, so changing that needs to show that the change is worth it. Maybe you can do that, even little cosmetic things can indeed be a win, but to write a convincing case here, you'll need to compare and contrast various cases.
Apr 09 2019
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
Another couple ideas you might get some traction on are making 
typeid() values be convertible back into typeof types iff CTFE.

That would let you use types as OOP class values in intermediate 
structures while still turning them back into template args later.

Not sure just how realistic that is, but might be fun to explore.


Related would be to use RTInfo in druntime to extend the typeid 
info to runtime data, based on a -version switch. This should be 
possible in today's language fairly easily, though it would not 
be customizable by the end user, you could perhaps just make it 
include it all.
Apr 09 2019
prev sibling parent Alex <AJ gmail.com> writes:
On Wednesday, 10 April 2019 at 02:19:42 UTC, Adam D. Ruppe wrote:
 On Tuesday, 9 April 2019 at 20:45:18 UTC, Alex wrote:
 On Tuesday, 9 April 2019 at 18:33:21 UTC, Seb wrote:
 Have you considered writing a DIP?
No, because I expect it won't even be considered.
You won't pass review if you don't show knowledge of the existing language, but there's a lot of people who are interested in a few changes. A few years ago, there was a proposal for a magical `meta` namespace that would call into the compiler for syntax sugar on CT reflection. The old idea was to replace `__traits(X, args)` with `meta.X(args)` - pure syntax change - but you could perhaps revive and expand that as the entry point to your new idea and get some people on board.
Yeah, but that isn't really effective, virtually identical. I am talking about one level higher abstraction. I mean, it's all the same but I'd like things to be sorta based in oop and ranges(UFCS like stuff). I haven't though about it enough to know how it would work out but I imagine things could be done very nicely. E.g., some accessors get information and some process that information and one can combine and match as needed. X.Type.name, X.Members.Select!"foo".Memebers.Select!"bar"(assuming foo is an aggregate), etc. Range functionality could even be used to process arrays(I guess the return of the traits would need to be ranges).
 I'm skeptical of any reflection library, but compiler changes 
 might be able to change that. The status quo for D's reflection 
 libraries are:

 1) weird bugs and/or omissions since the language does not let 
 you express all the function parameter details as return values 
 or local variables.

 2) slow compile times (you said your thing was 10 seconds! 
 that's utterly unacceptable)
It actually is not to bad. I haven't done much testing but at least repeatedly calling the Reflect on the same base type added little overhead(it wasn't scaling linearly with the number of calls). So maybe it has a chance. Still will never be as efficient as doing it internally though.
 3) not actually significantly easier to use than language 
 built-ins (if they are actually easier to use at all!)


 So any library without compiler changes is, as of today, I 
 believe *impossible* to get right, and getting as close as you 
 can is horribly slow. So, your DIP would necessarily include 
 language+compiler changes.

 And the compiler is *already* (almost) fully capable, so 
 changing that needs to show that the change is worth it. Maybe 
 you can do that, even little cosmetic things can indeed be a 
 win, but to write a convincing case here, you'll need to 
 compare and contrast various cases.
I'd definitely rather see this in the compiler. I just no zero about Dmd's design and the specifics. It's not something I'm capable of doing without a significant investment that I'm not willing to do(only if I could add the design on top without having to "learn" everything about the compiler). My goal was to sort of bridge the gap of the ideal solution and what we have. Something I could use personally to solve most of the frustrations I have but I wasn't thinking of trying to make it in to something ideal.
Apr 10 2019