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









"Nick Sabalausky" <a a.a> 