digitalmars.D - Idea For Attributes/Annotations
- Nick Sabalausky (59/59) Mar 10 2009 I've previously voiced my desire for something similar to C#'s attribute...
- Nick Sabalausky (6/18) Mar 10 2009 Ok, so apparently D2 phobos already has this in std.typecons (saw that i...
- Daniel Keep (6/26) Mar 10 2009 It produces this output:
- Daniel Keep (36/36) Mar 10 2009 On the syntax for D, a few thoughts:
(annotations in Java, IIRC), but that kind of got sidetracked into a discussion of command line parsers. I have another idea of a type of scenario where something like this would be very nice, and it also ties into the recent complaints of the mixin syntax being ugly. I just learned over on digitalmars.D.learn that D apparently has no general way to convert the value of an enum var to the actual string name of the value (at least not without making the underlying type a string containing it's own name, but that has obvious drawbacks). To illustrate: ------------- enum Shape { Square, Circle, Triangle } Shape s = Shape.Triangle; // Output is "2", but I want "Shape.Triangle" or "Triangle". // But there doesn't seem to be a way to do that currently. Stdout.formatln("{}", s); ------------- First of all, I would like to propose that we have some built-in way to do that. But that's not the main point of this post. The general case I'm looking at here is that this is an example of something that can only be accomplished (without violating DRY) by using a common mixin pattern: Instead of simply declaring what we want, we create and instantiate a mixin that generates our intended declaration and also any related boilerplate: ------------- // Something along these lines... template generateEnum(char[] name, values...) { const char[] generateEnum = "enum "~name~"{"~/*values*/~"}"~ "char[] enumToString("~name~" arg) { "~/*big switch(arg) here*/~"}"; } mixin(generateEnum!("Shape", "Square", "Circle", "Triangle")); Shape s = Shape.Triangle; Stdout.formatln("{}", enumToString (s)); ------------- Something along those lines would probably work (in fact, I've done similar things before). But, look what a mess that turns the enum's definition into! This is probably a good example of what people are thinking of when they call the mixin syntax ugly. So here's my idea: Allow the programmer to attach the desired boilerplate-generator to the *actual* definition, instead of generating the definition as part of the boilerplate-generator: ------------- // Actual syntax would probably differ, // But I'm thinking something along these general lines. [ GenerateEnumToString("some extra param")] enum Shape { Square, Circle, Triangle } // I really haven't throught through the syntax for this part annotation GenerateEnumToString(T : enum, char[] extraStuff) { const char[] func = "char[] enumToString("~name~" arg) { "~ /*big switch(arg) here, using compile-time reflection on T*/ ~"}"; mixin(func); } Shape s = Shape.Triangle; Stdout.formatln("{}", enumToString (s)); ------------- This way, we could do all the fancy mixin trickery we normally do, but in any case where something like this would be applicable, it wouldn't make the code look so terrible.
Mar 10 2009
"Nick Sabalausky" <a a.a> wrote in message news:gp78hj$b26$1 digitalmars.com...------------- // Something along these lines... template generateEnum(char[] name, values...) { const char[] generateEnum = "enum "~name~"{"~/*values*/~"}"~ "char[] enumToString("~name~" arg) { "~/*big switch(arg) here*/~"}"; } mixin(generateEnum!("Shape", "Square", "Circle", "Triangle")); Shape s = Shape.Triangle; Stdout.formatln("{}", enumToString (s)); -------------Ok, so apparently D2 phobos already has this in std.typecons (saw that in a reply over at ".D.learn"), but the main point of my post still remains. That point being, it looks terrible and annotations could make it (and anything similar) look not-terrible.
Mar 10 2009
For reference, Python has a concept called decorators. Take this function:def trace(fn): def __wrap(*pargs,**kwargs): print 'IN %s' % fn.__name__ r = fn(*pargs,**kwargs) print 'OUT %s' % fn.__name__ return r return __wrapAnd use it like so:trace def foo(msg): print 'Bar: %s' % msg return 42 print foo("baz")It produces this output:IN foo Bar: baz OUT foo 42And is equivalent to the following:def foo(msg): print 'Bar: %s' % msg return 42 foo = trace(foo)I believe either 2.5 or 3.0 adds this syntax to classes as well. -- Daniel
Mar 10 2009
On the syntax for D, a few thoughts: In Python, the decorator expression must evaluate to a function, which is then called with the function being decorated. We could do something similar in D. Let's change the syntax to this for now: (expr) decl Let's assume that expr must be a template. The template will be passed two arguments, although the second may be omitted. template foo(alias Decl, char[] src) { ... } Decl is an alias to whatever is being declared. This allows functions, classes, structs, enums, constants, etc. to be decorated. The second argument is the source code for that construct. So let's take an example: (foo) void bar(); If foo has a public member called 'foo', then the code is rewritten as: private void __decorated_bar; mixin foo!(__decorated_bar, "void bar();"); alias foo!(__decorated_bar, "void bar();").foo bar; Otherwise, it should be rewritten as: void bar(); mixin foo!(bar, "void bar();"); This would allow the decorator to, for example, generate a toString method for an enum without touching the enum itself, wrap a class, or both. A final idea, this: (expr) { decl_a; decl_b; } decl_c; (expr): decl_d; decl_e; Could be rewritten as: (expr) decl_a; (expr) decl_b; decl_c; (expr) decl_d; (expr) decl_e; -- Daniel
Mar 10 2009