www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - User defined attributes use

reply "matovitch" <camille.brugel laposte.net> writes:
Hi everyone,

I read the documentation about user defined attributes, but I 
don't see their uses. Ok, it'a a template expression you can link 
to a declaration, but what are they useful for ? (not sure about 
the syntax ;-))

Can you declare a template constraint as a user defined attribute 
to do something like :

void template_function_which_go_back_and_forth( ("Bidirectional") 
 ("Range") BR)(BR br) {...}

This would be awesome (even if not really occidental) to do 
something like:

 ("SmallTypeSet")  ("MediumTypeSet")  ("LargeTypeSet") Type

This could allow to build tree based category structure.
Sep 15 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-09-15 19:34, matovitch wrote:
 Hi everyone,

 I read the documentation about user defined attributes, but I don't see
 their uses.
I'm using it in my serialization library: struct Foo { int a; nonSerialized int b; } Indicates "b" will not be serialized. struct Bar { int a; onSerializing void foo () { // called when "Bar" is being serialized } } "foo" will be called when "Bar" is being serialized For another project I'm using it as part of a testing framework: describe("Lexer") { context("valid string literal") { it("should return a token with the type TokenKind.stringLiteral") unittest { auto code = `"asd"`; auto lexer = new Lexer(code); assert(lexer.scan.kind == TokenKind.stringLiteral); } } } -- /Jacob Carlborg
Sep 15 2013
prev sibling parent reply "simendsjo" <simendsjo gmail.com> writes:
On Sunday, 15 September 2013 at 17:34:06 UTC, matovitch wrote:
 Hi everyone,

 I read the documentation about user defined attributes, but I 
 don't see their uses. Ok, it'a a template expression you can 
 link to a declaration, but what are they useful for ? (not sure 
 about the syntax ;-))

 Can you declare a template constraint as a user defined 
 attribute to do something like :

 void 
 template_function_which_go_back_and_forth( ("Bidirectional") 
  ("Range") BR)(BR br) {...}

 This would be awesome (even if not really occidental) to do 
 something like:

  ("SmallTypeSet")  ("MediumTypeSet")  ("LargeTypeSet") Type

 This could allow to build tree based category structure.
It enables declarative programming. And because this is D, there is no runtime overhead. A common use is to add semantics to types and instances that is difficult or very intrusive to do by creating structs/classes by hand. A little validation example: nonNull // An instance shouldn't be allowed to be null class C { matches("[0-9]+") string someNumber; interval!"(]"(0, 10) // (0, 10] range int someInt; } C c; validate(c); // returns ["C is null", "someNumber doesn't match '[0-9]+'", "someInt is outside the interval '(0, 10]'"] And ORMs usually use annotations: table("some_tablename") class C { id("id_field_name") int id; } Take a look at C# and Java libraries to see how many uses attributes/annotations - they are still quite new in D, so they are still underutilized. A very big difference is of course that UDAs are available at compile time :)
Sep 15 2013
parent reply "ilya-stromberg" <ilya-stromberg-2009 yandex.ru> writes:
On Sunday, 15 September 2013 at 18:31:40 UTC, simendsjo wrote:
 On Sunday, 15 September 2013 at 17:34:06 UTC, matovitch wrote:
 Hi everyone,

 I read the documentation about user defined attributes, but I 
 don't see their uses. Ok, it'a a template expression you can 
 link to a declaration, but what are they useful for ? (not 
 sure about the syntax ;-))

 Can you declare a template constraint as a user defined 
 attribute to do something like :

 void 
 template_function_which_go_back_and_forth( ("Bidirectional") 
  ("Range") BR)(BR br) {...}

 This would be awesome (even if not really occidental) to do 
 something like:

  ("SmallTypeSet")  ("MediumTypeSet")  ("LargeTypeSet") Type

 This could allow to build tree based category structure.
It enables declarative programming. And because this is D, there is no runtime overhead. A common use is to add semantics to types and instances that is difficult or very intrusive to do by creating structs/classes by hand. A little validation example: nonNull // An instance shouldn't be allowed to be null class C { matches("[0-9]+") string someNumber; interval!"(]"(0, 10) // (0, 10] range int someInt; } C c; validate(c); // returns ["C is null", "someNumber doesn't match '[0-9]+'", "someInt is outside the interval '(0, 10]'"] And ORMs usually use annotations: table("some_tablename") class C { id("id_field_name") int id; } Take a look at C# and Java libraries to see how many uses attributes/annotations - they are still quite new in D, so they are still underutilized. A very big difference is of course that UDAs are available at compile time :)
Can you print a full examle? For example, can you implement "matches" UDA and validate function. It's intresting how can I create new UDA and check if it's available for class/field.
Sep 15 2013
parent reply "simendsjo" <simendsjo gmail.com> writes:
On Monday, 16 September 2013 at 06:47:40 UTC, ilya-stromberg 
wrote:
 On Sunday, 15 September 2013 at 18:31:40 UTC, simendsjo wrote:
 On Sunday, 15 September 2013 at 17:34:06 UTC, matovitch wrote:
 Hi everyone,

 I read the documentation about user defined attributes, but I 
 don't see their uses. Ok, it'a a template expression you can 
 link to a declaration, but what are they useful for ? (not 
 sure about the syntax ;-))

 Can you declare a template constraint as a user defined 
 attribute to do something like :

 void 
 template_function_which_go_back_and_forth( ("Bidirectional") 
  ("Range") BR)(BR br) {...}

 This would be awesome (even if not really occidental) to do 
 something like:

  ("SmallTypeSet")  ("MediumTypeSet")  ("LargeTypeSet") Type

 This could allow to build tree based category structure.
It enables declarative programming. And because this is D, there is no runtime overhead. A common use is to add semantics to types and instances that is difficult or very intrusive to do by creating structs/classes by hand. A little validation example: nonNull // An instance shouldn't be allowed to be null class C { matches("[0-9]+") string someNumber; interval!"(]"(0, 10) // (0, 10] range int someInt; } C c; validate(c); // returns ["C is null", "someNumber doesn't match '[0-9]+'", "someInt is outside the interval '(0, 10]'"] And ORMs usually use annotations: table("some_tablename") class C { id("id_field_name") int id; } Take a look at C# and Java libraries to see how many uses attributes/annotations - they are still quite new in D, so they are still underutilized. A very big difference is of course that UDAs are available at compile time :)
Can you print a full examle? For example, can you implement "matches" UDA and validate function. It's intresting how can I create new UDA and check if it's available for class/field.
I don't have a full example without adding a lot of code, but this partial example might give you the gist of it. // This is the type that validates struct matches(string mustMatch) { alias re = ctRegex!(mustMatch); static string[] validate(T)(const ref T t) { static if(!isSomeString!T) static assert(0, "matches only works on strings, not "~T.stringof); return match(t, re).empty ? ["no match"] : null; } } // and this is the code that runs all validators for a variable void validate(alias T)(ref Appender!(string[]) app) { static if(isTupleWrapper!T) { validate!(T.Head)(app); validate!(T.Tail)(app); } else { foreach(memberAttr; getValidaterAttrs!T) { foreach(attr; memberAttr.Tail) { foreach(msg; attr.validate(T)) if(msg.length) app.put(msg); } } } } // .. And here is some of the plumbing string[] validate(Vars...)() { auto app = appender!(string[])(); validate!Vars(app); return app.data(); } // The getMembersAndAttributesWhere are templates in my little library that isn't released. Uses quite some custom __traits stuff, but it's basically __traits(getAttributes template getValidaterAttrs(alias T) { alias getValidaterAttrs = TypeTuple!(getMembersAndAttributesWhere!(T, isValidationAttr).Elements, getMembersAndAttributesWhere!(TypeOf!T, isValidationAttr).Elements); } // Well.. Incomplete template isValidationAttr(alias T) { enum isValidationAttr = hasMember!(TypeOf!T, "validate"); }
Sep 16 2013
next sibling parent reply "matovitch" <camille.brugel laposte.net> writes:
All your examples are great, thank you ! Is there a way to omit 
validate such that the compiler would call it implicitly ?

For example :

class C {
   ...
}

void fun( nonNull C c) {
   ...
};

C c;
fun(c);  //compilation error since C is null
Sep 16 2013
next sibling parent reply "Bienlein" <jeti890 web.de> writes:
On Monday, 16 September 2013 at 10:29:12 UTC, matovitch wrote:
 All your examples are great, thank you ! Is there a way to omit 
 validate such that the compiler would call it implicitly ?

 For example :

 class C {
   ...
 }

 void fun( nonNull C c) {
   ...
 };

 C c;
 fun(c);  //compilation error since C is null
Very interesting. Does this go beyond annotations in Java? Just out of curiosity, no language war intended. -- Bienlein
Sep 16 2013
parent "matovitch" <camille.brugel laposte.net> writes:
On Monday, 16 September 2013 at 10:36:16 UTC, Bienlein wrote:
 On Monday, 16 September 2013 at 10:29:12 UTC, matovitch wrote:
 All your examples are great, thank you ! Is there a way to 
 omit validate such that the compiler would call it implicitly ?

 For example :

 class C {
  ...
 }

 void fun( nonNull C c) {
  ...
 };

 C c;
 fun(c);  //compilation error since C is null
Very interesting. Does this go beyond annotations in Java? Just out of curiosity, no language war intended. -- Bienlein
And with template parameters. fun( Arithmetic T)(...) {...} alias fun!string funstr; //compilation error since a string is not an arithmetic type
Sep 16 2013
prev sibling next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 16 September 2013 at 10:29:12 UTC, matovitch wrote:
 All your examples are great, thank you ! Is there a way to omit 
 validate such that the compiler would call it implicitly ?

 For example :

 class C {
   ...
 }

 void fun( nonNull C c) {
   ...
 };

 C c;
 fun(c);  //compilation error since C is null
No, this isn't doable with UDAs because what you want requires runtime check. It is doable using other language features.
Sep 16 2013
parent reply "ilya-stromberg" <ilya-stromberg-2009 yandex.ru> writes:
On Monday, 16 September 2013 at 15:12:05 UTC, Maxim Fomin wrote:
 On Monday, 16 September 2013 at 10:29:12 UTC, matovitch wrote:
 All your examples are great, thank you ! Is there a way to 
 omit validate such that the compiler would call it implicitly ?

 For example :

 class C {
  ...
 }

 void fun( nonNull C c) {
  ...
 };

 C c;
 fun(c);  //compilation error since C is null
No, this isn't doable with UDAs because what you want requires runtime check. It is doable using other language features.
It's intresting how can I check that pointer is not null at the compile time. Can you print a example, please? I know that we can use contract programming, but it requires runtime check.
Sep 16 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Monday, 16 September 2013 at 15:47:36 UTC, ilya-stromberg 
wrote:
 On Monday, 16 September 2013 at 15:12:05 UTC, Maxim Fomin wrote:
 On Monday, 16 September 2013 at 10:29:12 UTC, matovitch wrote:
 All your examples are great, thank you ! Is there a way to 
 omit validate such that the compiler would call it implicitly 
 ?

 For example :

 class C {
 ...
 }

 void fun( nonNull C c) {
 ...
 };

 C c;
 fun(c);  //compilation error since C is null
No, this isn't doable with UDAs because what you want requires runtime check. It is doable using other language features.
It's intresting how can I check that pointer is not null at the compile time. Can you print a example, please? I know that we can use contract programming, but it requires runtime check.
That isn't possible. ;)
Sep 16 2013
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 16 September 2013 at 16:50:43 UTC, Namespace wrote:
 On Monday, 16 September 2013 at 15:47:36 UTC, ilya-stromberg 
 wrote:
 On Monday, 16 September 2013 at 15:12:05 UTC, Maxim Fomin 
 wrote:
 On Monday, 16 September 2013 at 10:29:12 UTC, matovitch wrote:
 All your examples are great, thank you ! Is there a way to 
 omit validate such that the compiler would call it 
 implicitly ?

 For example :

 class C {
 ...
 }

 void fun( nonNull C c) {
 ...
 };

 C c;
 fun(c);  //compilation error since C is null
No, this isn't doable with UDAs because what you want requires runtime check. It is doable using other language features.
It's intresting how can I check that pointer is not null at the compile time. Can you print a example, please? I know that we can use contract programming, but it requires runtime check.
That isn't possible. ;)
Similar effect can be achieved by different way. If some function takes S as parameter, one cannot pass directly instance of A or null - error will be issued which is some sort of compile-time protection. class A { int i; } struct S { A a; A getA() { if (a is null) a = new A; return a; } alias getA this; } void main() { S s; assert (s.i is 0); S ss = S.init; assert (ss.i is 0); } Unfortunately D does not have non-nullable classes which is a problem #1. Ideally structs should have default constructors (hello to those who miss them - problem #2) which could initialize class instance. Since they are absent, wrapping struct can be enhanced by inserting disabled constructor to ensure that no default struct instances with null references are created. However, since disabled constructors are also flawed (they don't prevent from producing T.init values by design and in some situations dmd is not smart enough to detect other cases by mistake) which is a problem #3, non-null classes can be simulated by code above using alias this + rt check. At least this works with two most problematic cases of struct initilialization: without initializer and with T.init value.
Sep 16 2013
next sibling parent reply "ilya-stromberg" <ilya-stromberg-2009 yandex.ru> writes:
On Monday, 16 September 2013 at 17:50:16 UTC, Maxim Fomin wrote:
 Ideally structs should have default constructors (hello to 
 those who miss them - problem #2) which could initialize class 
 instance.
Do you know why D structs don't have default constructors? I really miss.
Sep 16 2013
parent "Namespace" <rswhite4 googlemail.com> writes:
On Monday, 16 September 2013 at 18:44:25 UTC, ilya-stromberg 
wrote:
 On Monday, 16 September 2013 at 17:50:16 UTC, Maxim Fomin wrote:
 Ideally structs should have default constructors (hello to 
 those who miss them - problem #2) which could initialize class 
 instance.
Do you know why D structs don't have default constructors? I really miss.
My favorites: http://forum.dlang.org/thread/ij6kl4$2jv9$1 digitalmars.com http://forum.dlang.org/thread/bvuquzwfykiytdwsqkky forum.dlang.org http://forum.dlang.org/thread/icjwbtlxsaekksyoljfp forum.dlang.org
Sep 16 2013
prev sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Monday, 16 September 2013 at 17:50:16 UTC, Maxim Fomin wrote:
 On Monday, 16 September 2013 at 16:50:43 UTC, Namespace wrote:
 On Monday, 16 September 2013 at 15:47:36 UTC, ilya-stromberg 
 wrote:
 On Monday, 16 September 2013 at 15:12:05 UTC, Maxim Fomin 
 wrote:
 On Monday, 16 September 2013 at 10:29:12 UTC, matovitch 
 wrote:
 All your examples are great, thank you ! Is there a way to 
 omit validate such that the compiler would call it 
 implicitly ?

 For example :

 class C {
 ...
 }

 void fun( nonNull C c) {
 ...
 };

 C c;
 fun(c);  //compilation error since C is null
No, this isn't doable with UDAs because what you want requires runtime check. It is doable using other language features.
It's intresting how can I check that pointer is not null at the compile time. Can you print a example, please? I know that we can use contract programming, but it requires runtime check.
That isn't possible. ;)
Similar effect can be achieved by different way. If some function takes S as parameter, one cannot pass directly instance of A or null - error will be issued which is some sort of compile-time protection. class A { int i; } struct S { A a; A getA() { if (a is null) a = new A; return a; } alias getA this; } void main() { S s; assert (s.i is 0); S ss = S.init; assert (ss.i is 0); } Unfortunately D does not have non-nullable classes which is a problem #1. Ideally structs should have default constructors (hello to those who miss them - problem #2) which could initialize class instance. Since they are absent, wrapping struct can be enhanced by inserting disabled constructor to ensure that no default struct instances with null references are created. However, since disabled constructors are also flawed (they don't prevent from producing T.init values by design and in some situations dmd is not smart enough to detect other cases by mistake) which is a problem #3, non-null classes can be simulated by code above using alias this + rt check. At least this works with two most problematic cases of struct initilialization: without initializer and with T.init value.
Yes, I know. Search for my name and not null, you will find many topics. I hate this NotNull struct hack. It is the same crap as the current scope solution. BTW: I'm curious which built-in feature will be removed next, maybe AA? An annotation like Foo! f would be much nicer than NotNull!Foo or NotNull Foo, but it would be an agreement. And I agree absolute, to disable default CTor's by struct's was a huge mistake. But D is full of those. ;)
Sep 16 2013
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 16, 2013 at 08:56:17PM +0200, Namespace wrote:
[...]
 I hate this NotNull struct hack. It is the same crap as the current
 scope solution. BTW: I'm curious which built-in feature will be
 removed next, maybe AA?
[...] That wouldn't be a bad idea, actually. The current AA implementation is so horribly broken, and so wrong in so many ways (there are at least 75 bugs related to AA's, some of the worst of which are 11037, 11025, 10916, 10525, 10381, 10380, 10046, just to name a few), that it would do a world of good to get rid of them altogether, and then reintroduce a properly-designed library solution for them. Of course, in the meantime everyone whose code breaks because of that will form a mob to lynch me, so I'll have to survive long enough to get the library solution working first. :-P T -- Microsoft is to operating systems & security ... what McDonalds is to gourmet cooking.
Sep 16 2013
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Monday, 16 September 2013 at 19:21:47 UTC, H. S. Teoh wrote:
 On Mon, Sep 16, 2013 at 08:56:17PM +0200, Namespace wrote:
 [...]
 I hate this NotNull struct hack. It is the same crap as the 
 current
 scope solution. BTW: I'm curious which built-in feature will be
 removed next, maybe AA?
[...] That wouldn't be a bad idea, actually. The current AA implementation is so horribly broken, and so wrong in so many ways (there are at least 75 bugs related to AA's, some of the worst of which are 11037, 11025, 10916, 10525, 10381, 10380, 10046, just to name a few), that it would do a world of good to get rid of them altogether, and then reintroduce a properly-designed library solution for them. Of course, in the meantime everyone whose code breaks because of that will form a mob to lynch me, so I'll have to survive long enough to get the library solution working first. :-P T
Built-in Arrays have also problems. What should we do? Remove and rewrite them also as library solution? With Arrays and AA's we would lose a lot of good differences to C++. Why should anyone switch to D if it is nothing else as a new C++?
Sep 16 2013
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Monday, 16 September 2013 at 19:58:51 UTC, Namespace wrote:
 Why should anyone switch to D if it is nothing else as a new 
 C++?
It's worth pointing out that the library AAs proposed here would still have the same syntax as the built-in ones now. int[string] a; would just be magically rewritten into AssociativeArray!(int, string) a; and ["one" : 1, "two" : 2], would just become something like AALiteral(["one", "two"], [1, 2]);, or whatever, I'm not sure exactly what they were going to do there. Anyway though, all the sugar is still there, just a new implementation as a regular D struct instead of a bunch of calls to _d_assocarray and the other dozen magic functions and typeinfo things it uses now. BTW part of the bugginess is because this move to the library was half-assed. It does do the AssocativeArray rewrite... but it also still uses the magic functions. So there's all kinds of weird crap going on that can make programs fail to link and other bugs since we've been stuck in this no-man's land for years.
Sep 16 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Monday, 16 September 2013 at 20:09:53 UTC, Adam D. Ruppe wrote:
 On Monday, 16 September 2013 at 19:58:51 UTC, Namespace wrote:
 Why should anyone switch to D if it is nothing else as a new 
 C++?
It's worth pointing out that the library AAs proposed here would still have the same syntax as the built-in ones now. int[string] a; would just be magically rewritten into AssociativeArray!(int, string) a; and ["one" : 1, "two" : 2], would just become something like AALiteral(["one", "two"], [1, 2]);, or whatever, I'm not sure exactly what they were going to do there.
Then of course I have not said anything. The same thing I would suggest for scope. It exists as a library solution and is rewritten magical.
Sep 16 2013
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Monday, 16 September 2013 at 20:15:26 UTC, Namespace wrote:
 On Monday, 16 September 2013 at 20:09:53 UTC, Adam D. Ruppe 
 wrote:
 On Monday, 16 September 2013 at 19:58:51 UTC, Namespace wrote:
 Why should anyone switch to D if it is nothing else as a new 
 C++?
It's worth pointing out that the library AAs proposed here would still have the same syntax as the built-in ones now. int[string] a; would just be magically rewritten into AssociativeArray!(int, string) a; and ["one" : 1, "two" : 2], would just become something like AALiteral(["one", "two"], [1, 2]);, or whatever, I'm not sure exactly what they were going to do there.
Then of course I have not said anything. The same thing I would suggest for scope. It exists as a library solution and is rewritten magical.
And maybe also for delete: we need something to delete the memory manually.
Sep 16 2013
parent "ilya-stromberg" <ilya-stromberg-2009 yandex.ru> writes:
On Monday, 16 September 2013 at 20:16:45 UTC, Namespace wrote:
 And maybe also for delete: we need something to delete the 
 memory manually.
And we need built-in memory allocators, not only GC.
Sep 16 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-09-16 22:15, Namespace wrote:

 Then of course I have not said anything.
 The same thing I would suggest for scope. It exists as a library
 solution and is rewritten magical.
I think the big difference here is that AA's are safe where "scope" is not. I agree with you, I like to use "scope" anyway. -- /Jacob Carlborg
Sep 16 2013
prev sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 09/16/13 21:58, Namespace wrote:
 On Monday, 16 September 2013 at 19:21:47 UTC, H. S. Teoh wrote:
 On Mon, Sep 16, 2013 at 08:56:17PM +0200, Namespace wrote:
 [...]
 I hate this NotNull struct hack. It is the same crap as the current
 scope solution. BTW: I'm curious which built-in feature will be
 removed next, maybe AA?
[...] That wouldn't be a bad idea, actually. The current AA implementation is so horribly broken, and so wrong in so many ways (there are at least 75
[...]
 Built-in Arrays have also problems.
 What should we do? Remove and rewrite them also as library solution?
Yes. Without any doubt whatsoever. [1]
 With Arrays and AA's we would lose a lot of good differences to C++.
Removing hardwired builtin magic does not imply syntax changes. And, the syntax that matters in practice is not the declarations, but the literals, which is where the language could do much better anyway.
 Why should anyone switch to D if it is nothing else as a new C++?
D is not only about arrays. artur [1] Obviously, not a practical short term option for the existing D2 language. That's probably clear from the context, and the question was meant to be rhetorical -- but it could actually be done and would make sense; it's just not a change that would make enough of a difference on its own; the cost would be to high.
Sep 16 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
 D is not only about arrays.
It's a big plus. ;)
 [1] Obviously, not a practical short term option for the 
 existing D2 language.
     That's probably clear from the context, and the question 
 was meant to be
     rhetorical -- but it could actually be done and would make 
 sense; it's just
     not a change that would make enough of a difference on its 
 own; the cost
     would be to high.
Why to high? Too much compiler magic or dmd internal dependences?
Sep 16 2013
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 16, 2013 at 10:38:58PM +0200, Namespace wrote:
D is not only about arrays.
It's a big plus. ;)
[1] Obviously, not a practical short term option for the existing D2
language.  That's probably clear from the context, and the question
was meant to be rhetorical -- but it could actually be done and would
make sense; it's just not a change that would make enough of a
difference on its own; the cost would be to high.
Why to high? Too much compiler magic or dmd internal dependences?
I disagree that it's too high. It just needs *somebody* with the right knowledge about DMD internals (and enough free time on their hands >:-)) to pull it off. The problem with the current AA implementation is that it's schizophrenically split across DMD, aaA.d, and object.di. Martin Nowak recently cleaned it up somewhat (removed the horrible code duplication between aaA.d and object.di that used to be there) but fundamental issues remain, a major cause of which is the fact that aaA.d operates on typeinfo's rather than the direct types (this isn't a problem in and of itself, but the problem is that *only* AA keys have the benefit of their typeinfo's being available to AA functions, which means AA *values* that require non-trivial postblits and other such things are fundamentally broken in horrible ways). Moreover, DMD still retains way too much knowledge about AA internals, so sometimes it gets mapped to struct AssociativeArray, sometimes directly mapped to aaA.d, and sometimes a buggy inconsistent mixture of both. And the code that emits these different schizophrenic parts are sprinkled all over different unrelated parts of DMD, making any cleanup attempt rather challenging, to say the least. And of course, any non-correspondence between any of these parts means yet another AA bug waiting to happen. Cleaning up this mess once and for all will unquestionably do a world of good to D. T -- You are only young once, but you can stay immature indefinitely. -- azephrahel
Sep 16 2013
prev sibling next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 09/16/13 22:38, Namespace wrote:
 [1] Obviously, not a practical short term option for the existing D2 language.
     That's probably clear from the context, and the question was meant to be
     rhetorical -- but it could actually be done and would make sense; it's just
     not a change that would make enough of a difference on its own; the cost
     would be to high.
Why to high? Too much compiler magic or dmd internal dependences?
Too much (language) change for too little gain; there are many, many much more important things that need to be fixed. Being able to have several user-defined kinds of arrays is a nice-to-have feature, but not one that determines whether the language is usable or not. artur
Sep 16 2013
prev sibling next sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 09/16/13 22:52, H. S. Teoh wrote:
 On Mon, Sep 16, 2013 at 10:38:58PM +0200, Namespace wrote:
 D is not only about arrays.
It's a big plus. ;)
 [1] Obviously, not a practical short term option for the existing D2
 language.  That's probably clear from the context, and the question
 was meant to be rhetorical -- but it could actually be done and would
 make sense; it's just not a change that would make enough of a
 difference on its own; the cost would be to high.
Why to high? Too much compiler magic or dmd internal dependences?
I disagree that it's too high. It just needs *somebody* with the right knowledge about DMD internals (and enough free time on their hands >:-)) to pull it off.
I thought (s)he was asking about *arrays*, not AAs. There's no disagreement about removing AA magic - that does not involve language changes. artur
Sep 16 2013
parent "Namespace" <rswhite4 googlemail.com> writes:
On Monday, 16 September 2013 at 21:11:00 UTC, Artur Skawina wrote:
 On 09/16/13 22:52, H. S. Teoh wrote:
 On Mon, Sep 16, 2013 at 10:38:58PM +0200, Namespace wrote:
 D is not only about arrays.
It's a big plus. ;)
 [1] Obviously, not a practical short term option for the 
 existing D2
 language.  That's probably clear from the context, and the 
 question
 was meant to be rhetorical -- but it could actually be done 
 and would
 make sense; it's just not a change that would make enough of 
 a
 difference on its own; the cost would be to high.
Why to high? Too much compiler magic or dmd internal dependences?
I disagree that it's too high. It just needs *somebody* with the right knowledge about DMD internals (and enough free time on their hands >:-)) to pull it off.
I thought (s)he was asking about *arrays*, not AAs. There's no disagreement about removing AA magic - that does not involve language changes. artur
Yes, he was. ;) Thanks for explanation.
Sep 16 2013
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 16, 2013 at 10:59:10PM +0200, Artur Skawina wrote:
 On 09/16/13 22:38, Namespace wrote:
 [1] Obviously, not a practical short term option for the existing
     D2 language.  That's probably clear from the context, and the
     question was meant to be rhetorical -- but it could actually be
     done and would make sense; it's just not a change that would
     make enough of a difference on its own; the cost would be to
     high.
Why to high? Too much compiler magic or dmd internal dependences?
Too much (language) change for too little gain; there are many, many much more important things that need to be fixed. Being able to have several user-defined kinds of arrays is a nice-to-have feature, but not one that determines whether the language is usable or not.
[...] Hmm. I find D arrays just fine the way they are, actually. (In fact, I rather *liked* the way D arrays worked as compared with, say, C/C++.) What's wrong with them? T -- Famous last words: I *think* this will work...
Sep 16 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-09-17 00:53, H. S. Teoh wrote:

 Hmm. I find D arrays just fine the way they are, actually. (In fact, I
 rather *liked* the way D arrays worked as compared with, say, C/C++.)
 What's wrong with them?
I guess one can complain about some of the built-in properties/functions, like sort. -- /Jacob Carlborg
Sep 16 2013
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 09/17/13 00:53, H. S. Teoh wrote:
 On Mon, Sep 16, 2013 at 10:59:10PM +0200, Artur Skawina wrote:
 On 09/16/13 22:38, Namespace wrote:
 [1] Obviously, not a practical short term option for the existing
     D2 language.  That's probably clear from the context, and the
     question was meant to be rhetorical -- but it could actually be
     done and would make sense; it's just not a change that would
     make enough of a difference on its own; the cost would be to
     high.
Why to high? Too much compiler magic or dmd internal dependences?
Too much (language) change for too little gain; there are many, many much more important things that need to be fixed. Being able to have several user-defined kinds of arrays is a nice-to-have feature, but not one that determines whether the language is usable or not.
[...] Hmm. I find D arrays just fine the way they are, actually. (In fact, I rather *liked* the way D arrays worked as compared with, say, C/C++.) What's wrong with them?
Not that much, at least not enough to worry about it right now, considering all the other language issues. (eg some conversions, like to-bool, static-array-to-slice; syntax ambiguity [1]; some properties) But removing magic from the compiler and making the language more expressive, so that the magic could be done by the user, would be an improvement. Not a regression, which the original question implied. For example: 1) // in semi-pseudocode alias utf8string = utf8octet[]; utf8string s = "abc"; foreach (c; s) // iterate by codepoints, not bytes Yep, this is like what can be done today with built-in strings -- except that it could be done by overloading array-ops in 'utf8octect'. No type-specific compiler magic, and then you can use it for many other kinds of variable-element-length array types. 2) SIMD optimizations; again, w/o explicit compiler support. It could just map array ops to an optional 'static inline T.opArrayOp(string op, size_t minAlignent, B)(T[] a, B b)' method, etc. In general, much of the built-in compiler 'magic' gets in the way of emitting optimal code, for example the hardwired (d)runtime calls prevent many optimizations. (eg removing (hacking around for just one built-in type is easy enough) the 'typeid()' calls from your stand-alone AAs makes a huge difference. Or at least it did ~ a year ago when i looked at how much inherent overhead the std AAs have). artur [1] ---------------------------------------------------------------------- auto f(T[2] a) { /* 'a' is what it looks like - a static array, right? Oops... */ } template Tuple(A...) { alias Tuple = A; } alias T = Tuple!(int, double, long); ----------------------------------------------------------------------
Sep 17 2013
prev sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 16 September 2013 at 19:21:47 UTC, H. S. Teoh wrote:
 On Mon, Sep 16, 2013 at 08:56:17PM +0200, Namespace wrote:
 [...]
 I hate this NotNull struct hack. It is the same crap as the 
 current
 scope solution. BTW: I'm curious which built-in feature will be
 removed next, maybe AA?
[...] That wouldn't be a bad idea, actually. The current AA implementation is so horribly broken, and so wrong in so many ways (there are at least 75 bugs related to AA's, some of the worst of which are 11037, 11025, 10916, 10525, 10381, 10380, 10046, just to name a few), that it would do a world of good to get rid of them altogether, and then reintroduce a properly-designed library solution for them. Of course, in the meantime everyone whose code breaks because of that will form a mob to lynch me, so I'll have to survive long enough to get the library solution working first. :-P T
This demonstrates an interesting issue. I think the primary reason why you are complaining about AAs is not because their implementation is flawed but because you can't fix it without dmd's internals knowledge :) I always consider ability to hack dmd as important skill (at least in better language understanding because it is not defined by standard but by reference implementation) in D and that's why I am skeptical about many ideas proposed in form of DIPs - (unless they are proposed by those folks whose names often appear in dmd git commit log) because such proposals are not implementable without dmd's knowledge. I remember one point made recently by one regular D forum participant that it is more important 'to know the language itself', 'to be abstract from one particular implementation' rather then knowing 'dirty implementation details' to propose DIPs and that those who know dmd will eventually implement DIPs - yet number of DIPs is close to 50 and judging by ratio implemented DIPs/total DIPs it obvious that such assumption doesn't hold. As a result community is stuck with many features of language are flawed but they can be hardly fixed - plenty discussions and DIPs are generated but problems are not moved by an inch. I think if a person who has druntime/phobos commits to fix some issue but no dmd's one should ask in a forum thread/directly address to Walter/Kenji for a help request (addressing Walter should happen without hesitation because he is the first to be blamed :) ).
Sep 16 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/16/13 11:56 AM, Namespace wrote:
 I hate this NotNull struct hack. It is the same crap as the current
 scope solution.
Scoped variables in the language were a lot worse.
 BTW: I'm curious which built-in feature will be removed
 next, maybe AA?
If we're diligent and lucky, hopefully.
 An annotation like Foo! f would be much nicer than NotNull!Foo or
  NotNull Foo, but it would be an agreement.
Is annotation the only or main problem?
 And I agree absolute, to disable default CTor's by struct's was a huge
 mistake. But D is full of those. ;)
They are not disabled. It seems many people are having trouble with getting default constructors to evaluate code, so I assume you mean that. One possibility (or first step) would be to relax the language to allow CTFE-executable code in default constructors. Andrei
Sep 16 2013
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 16, 2013 at 12:28:21PM -0700, Andrei Alexandrescu wrote:
 On 9/16/13 11:56 AM, Namespace wrote:
I hate this NotNull struct hack. It is the same crap as the current
scope solution.
Scoped variables in the language were a lot worse.
One thing I'd *really* like to have is proper escape analysis and inlining of scope delegates. I've been waiting a long time for this, and there are no signs of implementation in sight. :-(
BTW: I'm curious which built-in feature will be removed
next, maybe AA?
If we're diligent and lucky, hopefully.
I don't see what luck has to do with it... Currently, I lack just time and adequate understanding of DMD internals; if I had both, I'd rip out the AA implementation from DMD right now, and replace it with something saner. [...]
And I agree absolute, to disable default CTor's by struct's was a
huge mistake. But D is full of those. ;)
They are not disabled.
[...] Huh, what? struct S { this() {} } DMD output: /tmp/test.d(2): Error: constructor test.S.this default constructor for structs only allowed with disable and no body T -- You are only young once, but you can stay immature indefinitely. -- azephrahel
Sep 16 2013
prev sibling next sibling parent "ilya-stromberg" <ilya-stromberg-2009 yandex.ru> writes:
On Monday, 16 September 2013 at 19:28:22 UTC, Andrei Alexandrescu 
wrote:
 On 9/16/13 11:56 AM, Namespace wrote:
 And I agree absolute, to disable default CTor's by struct's 
 was a huge
 mistake. But D is full of those. ;)
They are not disabled. It seems many people are having trouble with getting default constructors to evaluate code, so I assume you mean that. One possibility (or first step) would be to relax the language to allow CTFE-executable code in default constructors.
Yes, we REALLY need this. I know that we can init struct fields via user-defined value, but for many cases is not enough. And in that days I remembered C++. Buy the way, what does it mean "They are not disabled"? struct Foo { int i = 5; //works } struct Bar { int i; this() { i = 5; } } DMD: src/app.d(10): Error: constructor app.Bar.this default constructor for structs only allowed with disable and no body
Sep 16 2013
prev sibling parent "Namespace" <rswhite4 googlemail.com> writes:
Long time not heard from each other. ;)

On Monday, 16 September 2013 at 19:28:22 UTC, Andrei Alexandrescu 
wrote:
 On 9/16/13 11:56 AM, Namespace wrote:
 I hate this NotNull struct hack. It is the same crap as the 
 current
 scope solution.
Scoped variables in the language were a lot worse.
Why? The escaping problem could be solved, not? Wouldn't it be better, if scope would stay and would be rewritten internal to the library solution? The compiler could then detect and solve many of the current problems.
 BTW: I'm curious which built-in feature will be removed
 next, maybe AA?
If we're diligent and lucky, hopefully.
That was a joke of me. So I hope that is also a joke. Otherwise it would be a huge step in the C++ direction. If it wasn't a joke: what are the rationale for that?
 An annotation like Foo! f would be much nicer than NotNull!Foo 
 or
  NotNull Foo, but it would be an agreement.
Is annotation the only or main problem?
My problem are the nullable classes. But I would be happy with an annotation.
 And I agree absolute, to disable default CTor's by struct's 
 was a huge
 mistake. But D is full of those. ;)
They are not disabled. It seems many people are having trouble with getting default constructors to evaluate code, so I assume you mean that. One possibility (or first step) would be to relax the language to allow CTFE-executable code in default constructors. Andrei
Example?
Sep 16 2013
prev sibling parent "simendsjo" <simendsjo gmail.com> writes:
On Monday, 16 September 2013 at 10:29:12 UTC, matovitch wrote:
 All your examples are great, thank you ! Is there a way to omit 
 validate such that the compiler would call it implicitly ?

 For example :

 class C {
   ...
 }

 void fun( nonNull C c) {
   ...
 };

 C c;
 fun(c);  //compilation error since C is null
As others have noted, the compiler cannot know what any of your attributes mean. But you can do this: class C { invariant() { validate(this); } }
Sep 16 2013
prev sibling parent reply "ilya-stromberg" <ilya-stromberg-2009 yandex.ru> writes:
On Monday, 16 September 2013 at 07:36:13 UTC, simendsjo wrote:
 I don't have a full example without adding a lot of code, but 
 this partial
 example might give you the gist of it.


 // This is the type that validates
 struct matches(string mustMatch)
 {
     alias re = ctRegex!(mustMatch);

     static string[] validate(T)(const ref T t)
     {
         static if(!isSomeString!T)
             static assert(0, "matches only works on strings, 
 not "~T.stringof);
         return match(t, re).empty ? ["no match"] : null;
     }
 }

 // and this is the code that runs all validators for a variable
 void validate(alias T)(ref Appender!(string[]) app)
 {
     static if(isTupleWrapper!T)
     {
         validate!(T.Head)(app);
         validate!(T.Tail)(app);
     }
     else
     {
         foreach(memberAttr; getValidaterAttrs!T)
         {
             foreach(attr; memberAttr.Tail)
             {
                 foreach(msg; attr.validate(T))
                     if(msg.length)
                         app.put(msg);
             }
         }
     }
 }

 // .. And here is some of the plumbing

 string[] validate(Vars...)()
 {
     auto app = appender!(string[])();
     validate!Vars(app);
     return app.data();
 }


 // The getMembersAndAttributesWhere are templates in my little 
 library that isn't released. Uses quite some custom __traits 
 stuff, but it's basically __traits(getAttributes
 template getValidaterAttrs(alias T)
 {
     alias getValidaterAttrs = 
 TypeTuple!(getMembersAndAttributesWhere!(T, 
 isValidationAttr).Elements,
                                          
 getMembersAndAttributesWhere!(TypeOf!T, 
 isValidationAttr).Elements);
 }

 // Well.. Incomplete
 template isValidationAttr(alias T)
 {
     enum isValidationAttr = hasMember!(TypeOf!T, "validate");
 }
Can I explicitly specify when I can use attribute? Something like this: attribute("field") struct matches(string mustMatch) { } string wrongAttribute { } class Foo { matches("[0-9]+") string someNumber; //OK, it's a field } matches("[0-9]+") //Error, it's a class, not a field class Bar { } wrongAttribute //Error, this attribute doesn't exist class C { }
Sep 19 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-09-20 08:59, ilya-stromberg wrote:

 Can I explicitly specify when I can use attribute? Something like
 this:

  attribute("field")
 struct matches(string mustMatch)
 {
 }

 string wrongAttribute
 {
 }

 class Foo
 {
       matches("[0-9]+")
      string someNumber; //OK, it's a field
 }

  matches("[0-9]+") //Error, it's a class, not a field
 class Bar
 {
 }

  wrongAttribute //Error, this attribute doesn't exist
 class C
 {
 }
Unfortunately you can't. I tag all my structs which are supposed to be used as UDA's with a attribute UDA. struct attribute {} attribute struct matches(string mustMatch) {} Then I have some wrappers around __traits(getAttributes) that will, by default, only return UDA's that them self have the attribute UDA attached to them. https://github.com/jacob-carlborg/orange/blob/master/orange/core/Attribute.d -- /Jacob Carlborg
Sep 20 2013
parent reply "simendsjo" <simendsjo gmail.com> writes:
On Friday, 20 September 2013 at 07:57:43 UTC, Jacob Carlborg 
wrote:
 On 2013-09-20 08:59, ilya-stromberg wrote:

 Can I explicitly specify when I can use attribute? Something 
 like
 this:

  attribute("field")
 struct matches(string mustMatch)
 {
 }

 string wrongAttribute
 {
 }

 class Foo
 {
      matches("[0-9]+")
     string someNumber; //OK, it's a field
 }

  matches("[0-9]+") //Error, it's a class, not a field
 class Bar
 {
 }

  wrongAttribute //Error, this attribute doesn't exist
 class C
 {
 }
Unfortunately you can't. I tag all my structs which are supposed to be used as UDA's with a attribute UDA. struct attribute {} attribute struct matches(string mustMatch) {} Then I have some wrappers around __traits(getAttributes) that will, by default, only return UDA's that them self have the attribute UDA attached to them. https://github.com/jacob-carlborg/orange/blob/master/orange/core/Attribute.d
You could of course fix this in a library too. enum AttributeUsage { struct_ = 1 << 0, class_ = 1 << 1, //etc } struct attribute { AttributeUsage usage; } Then the library could give a compile-time error if you tries to use it where it's not meant to be.
Sep 20 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-09-20 16:12, simendsjo wrote:

 You could of course fix this in a library too.

 enum AttributeUsage {
    struct_ = 1 << 0,
    class_ = 1 << 1,
    //etc
 }

 struct attribute { AttributeUsage usage; }

 Then the library could give a compile-time error if you tries to use it
 where it's not meant to be.
I'm not sure how I could do that. -- /Jacob Carlborg
Sep 23 2013
parent "simendsjo" <simendsjo gmail.com> writes:
On Monday, 23 September 2013 at 07:47:32 UTC, Jacob Carlborg 
wrote:
 On 2013-09-20 16:12, simendsjo wrote:

 You could of course fix this in a library too.

 enum AttributeUsage {
   struct_ = 1 << 0,
   class_ = 1 << 1,
   //etc
 }

 struct attribute { AttributeUsage usage; }

 Then the library could give a compile-time error if you tries 
 to use it
 where it's not meant to be.
I'm not sure how I could do that.
You can recurse into UDAs for attributes and pass along the type that had the uda. A static assert could verify that it's used on the correct type. (For my library, that would mean editing my getMembersAndAttributes template.)
Sep 23 2013