digitalmars.D.learn - Is it possible to use an UDA to generate a struct inside a class ?
- Basile Burg (41/41) Dec 30 2014 I have a struct used to describe a property[1].
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (71/72) Dec 30 2014 Here is a quick and dirty solution:
- Basile Burg (4/79) Dec 30 2014 Introspection inside each class. I don't find this solution ugly
- Basile Burg (6/12) Jan 01 2015 i've chosen another way to do that but it unleashes an ICE (every
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (23/30) Jan 01 2015 Yes, the compiler should never crash but produce an error message.
- Basile Burg (19/29) Jan 01 2015 The report is filed. I was not sure of its validity or if it
- BBaz (9/42) Jan 30 2015 This was the way to go (the relative-offset "thing"):
I have a struct used to describe a property[1]. Its standard usage is represented in this simple example: |class Bar { | private uint fField0; | private izPropDescriptor!uint descrField0; | this() { | descrField0.define(&field0, &field0, "field0"); | } | public void field0(uint aValue) {fField0 = aValue;} | public uint field0(){return fField0;} |} The descriptor is used by a property binding system or a serializer. The problem is that declaring a property descriptor is **very** repetitive. I've always wanted to find a way to generate a descriptor automatically, and finally today, while reading some random things on GH, I've "found" that the annotation system used in HibernateD[2] could be used. So far I didnt get the point of UDA and never used them. So I've created a basic UDA but, and then ? Can a descriptor be created using my "attribute" ? How ? |struct Setter { | const char[] propertyName; |} |struct Getter { | const char[] propertyName; |} |class Foo { | private uint fField0; | public Setter("field0") void field0(uint aValue) { | fField0 = aValue; | } | public Getter("field0") uint field0(){ | return fField0; | } |} ------------------------ [1]:https://github.com/BBasile/Iz/blob/master/import/iz/properties.d#L27 [2]:https://github.com/buggins/hibernated/blob/master/source/hibernated/annotations.d#L15
Dec 30 2014
On 12/30/2014 09:42 AM, Basile Burg wrote:Can a descriptor be created using my "attribute" ? How ?Here is a quick and dirty solution: import std.string; struct PropertyDescriptor { string type; string name; string memberName() property const { return name ~ "_"; } string definition() property const { return format("%s %s;", type, memberName); } string getter() property const { return format("%s %s() property const { return %s; }", type, name, memberName); } string setter() property const { return format("void %s(%s value) property { %s = value; }", name, type, memberName); } } unittest { const descr = PropertyDescriptor("int", "foo"); assert(descr.memberName == "foo_"); assert(descr.definition == q{int foo_;}); assert(descr.getter == q{int foo() property const { return foo_; }}); assert(descr.setter == q{void foo(int value) property { foo_ = value; }}); } struct Property { PropertyDescriptor[] properties; string propertyCode() property const { string result; foreach (property; properties) { result ~= property.definition ~ property.getter ~ property.setter; } return result; } } string propertyInjections(T)() { string result; foreach (attr; __traits(getAttributes, T)) { static if (is (typeof(attr) == Property)) { result ~= attr.propertyCode; } } return result; } Property([ PropertyDescriptor("int", "i"), PropertyDescriptor("double", "d") ]) class C { mixin (propertyInjections!C); } void main() { auto c = new C(); c.i = 42; assert(c.i == 42); } Ali
Dec 30 2014
On Tuesday, 30 December 2014 at 19:05:23 UTC, Ali Çehreli wrote:On 12/30/2014 09:42 AM, Basile Burg wrote:Ok, thx. I see the trick:Can a descriptor be created using my "attribute" ? How ?Here is a quick and dirty solution: import std.string; struct PropertyDescriptor { string type; string name; string memberName() property const { return name ~ "_"; } string definition() property const { return format("%s %s;", type, memberName); } string getter() property const { return format("%s %s() property const { return %s; }", type, name, memberName); } string setter() property const { return format("void %s(%s value) property { %s = value; }", name, type, memberName); } } unittest { const descr = PropertyDescriptor("int", "foo"); assert(descr.memberName == "foo_"); assert(descr.definition == q{int foo_;}); assert(descr.getter == q{int foo() property const { return foo_; }}); assert(descr.setter == q{void foo(int value) property { foo_ = value; }}); } struct Property { PropertyDescriptor[] properties; string propertyCode() property const { string result; foreach (property; properties) { result ~= property.definition ~ property.getter ~ property.setter; } return result; } } string propertyInjections(T)() { string result; foreach (attr; __traits(getAttributes, T)) { static if (is (typeof(attr) == Property)) { result ~= attr.propertyCode; } } return result; } Property([ PropertyDescriptor("int", "i"), PropertyDescriptor("double", "d") ]) class C { mixin (propertyInjections!C); } void main() { auto c = new C(); c.i = 42; assert(c.i == 42); } Alimixin (propertyInjections!C);Introspection inside each class. I don't find this solution ugly btw. I think there is no other way to do this.
Dec 30 2014
On Tuesday, 30 December 2014 at 19:18:41 UTC, Basile Burg wrote:On Tuesday, 30 December 2014 at 19:05:23 UTC, Ali Çehreli wrote:i've chosen another way to do that but it unleashes an ICE (every compiler crash is an ICE right ?), not tested on trunk: http://dpaste.dzfl.pl/70ab707b21e4 e.g I try to get the getter delegate in order to set a new izPropDescriptor in an AA.On 12/30/2014 09:42 AM, Basile Burg wrote:Ok, thx. I see the trick:mixin (propertyInjections!C);Introspection inside each class. I don't find this solution ugly btw. I think there is no other way to do this.
Jan 01 2015
On 01/01/2015 09:35 AM, Basile Burg wrote:On Tuesday, 30 December 2014 at 19:18:41 UTC, Basile Burg wrote:an ICE (every compiler crash is an ICE right ?),Yes, the compiler should never crash but produce an error message. Please report it preferably with a reduced code sample: https://issues.dlang.org/not tested on trunk:It has the same problem on git head.http://dpaste.dzfl.pl/70ab707b21e4 e.g I try to get the getter delegate in order to set a new izPropDescriptor in an AA.foreach(m; __traits(allMembers, tp)) { foreach(o; __traits(getOverloads, tp, m)) { foreach(attr; __traits(getAttributes, o)) { static if (is(attr == get)) { writeln(attr.stringof, " < ", m); alias PT = ReturnType!o; //auto ICE = &o; //comment = no crash You realize, all of those foreach'es are processed at compile-time for code generation. There will be no 'o' at run time; so its address cannot be used. The compiler problem is probably related to that. } else if (is(attr == set)) { You probably want that to be 'else static if'. Otherwise, when the previous 'static if' fails the condition, there will be an 'if' statement inserted, which would get executed at run time. void main(string args[]){ Compiling with the -w compiler switch produces the following warning: Warning: instead of C-style syntax, use D-style syntax 'string[] args' Ali
Jan 01 2015
On Thursday, 1 January 2015 at 21:15:27 UTC, Ali Çehreli wrote:On 01/01/2015 09:35 AM, Basile Burg wrote:The report is filed. I was not sure of its validity or if it could be a dup. -----------------On Tuesday, 30 December 2014 at 19:18:41 UTC, Basile Burgwrote:an ICE (every compiler crash is an ICE right ?),Yes, the compiler should never crash but produce an error message. Please report it preferably with a reduced code sample:You realize, all of those foreach'es are processed at compile-time for code generation. There will be no 'o' at run time; so its address cannot be used.Instead, Can I get the *relative offset* of a particular member at compile-time ? Then at run-time I could easily define the delegate, eg: // the AA or some arrays filled at compile-time ptrdiff_t[string] gettersOffset; ptrdiff_t[string] settersOffset; // a delegate, set at run-time, for example in this(). myDelegate.funcptr = gettersOffset["propIdentifier"]; myDelegate.ptr = cast(void*) this; If so then the problem is solved...even if other problems could appends, for example if the methods are final, if they are inlined... Actually I'd be surprised that nobody has already designed something similar for properties (kind of "published" attribute as defined in Pascal-like languages.)
Jan 01 2015
On Thursday, 1 January 2015 at 22:49:40 UTC, Basile Burg wrote:On Thursday, 1 January 2015 at 21:15:27 UTC, Ali Çehreli wrote:This was the way to go (the relative-offset "thing"): 1/ __traits(getVirtualIndex,...) works at compile time 2/ then the method pointer can be constructed using vtbl And it works, though I'm still open to another solution (since now the get/set >>must<< be virtual) Current implementation: https://github.com/BBasile/Iz/blob/master/import/iz/properties.d#L383 :)On 01/01/2015 09:35 AM, Basile Burg wrote:The report is filed. I was not sure of its validity or if it could be a dup. -----------------On Tuesday, 30 December 2014 at 19:18:41 UTC, Basile Burgwrote:an ICE (every compiler crash is an ICE right ?),Yes, the compiler should never crash but produce an error message. Please report it preferably with a reduced code sample:You realize, all of those foreach'es are processed at compile-time for code generation. There will be no 'o' at run time; so its address cannot be used.Instead, Can I get the *relative offset* of a particular member at compile-time ? Then at run-time I could easily define the delegate, eg: // the AA or some arrays filled at compile-time ptrdiff_t[string] gettersOffset; ptrdiff_t[string] settersOffset; // a delegate, set at run-time, for example in this(). myDelegate.funcptr = gettersOffset["propIdentifier"]; myDelegate.ptr = cast(void*) this; If so then the problem is solved...even if other problems could appends, for example if the methods are final, if they are inlined... Actually I'd be surprised that nobody has already designed something similar for properties (kind of "published" attribute as defined in Pascal-like languages.)
Jan 30 2015