www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Modifying user-defined attributes. UDA templates.

reply "Yuriy" <yuriy.glukhov gmail.com> writes:
Hello, I'm new to D, so please excuse me if i'm wrong anywhere. 
Ever since i've learned C++ and started practicing templates 
metaprogramming (after reading Andrei's book) i wished there was 
a language to be low-level as C++, productive as if interpreted 
(e.g. Python), and expressive as... well... here comes D! It's 
features are great, and specifically now i want to talk about 
UDA. This feature is what i lacked in C++, but as you know, 
appetite comes with eating, so i think there's still room for 
improvement in UDAs.

The problem is current UDAs can't modify definition they're 
attached to. The solution is somewhere near Python's decorators, 
but of course, using compile-time templates or mixins.

Here's an example:

template MyAttr(string name, T)
{

}

 MyAttr class MyClass
{
  ... class body
}

Which should evaluate to something like:
class __MyClassTmpThatWillBeRemovedInCompileTime
{
  ... class body
}

mixin(MyAttr!("MyClass", 
__MyClassTmpThatWillBeRemovedInCompileTime));

Next, MyAttr can modify the class, rename it, ignore it (in this 
case MyClass will not be available further), define something 
else instead of it.
I could try and modify dmd to support it at least as a prototype, 
but before, i'd like to know whether such feature was already 
considered and rejected. Thanx.
Mar 17 2014
next sibling parent reply "Jacob Carlborg" <doob me.com> writes:
On Monday, 17 March 2014 at 09:17:33 UTC, Yuriy wrote:
 Hello, I'm new to D, so please excuse me if i'm wrong anywhere. 
 Ever since i've learned C++ and started practicing templates 
 metaprogramming (after reading Andrei's book) i wished there 
 was a language to be low-level as C++, productive as if 
 interpreted (e.g. Python), and expressive as... well... here 
 comes D! It's features are great, and specifically now i want 
 to talk about UDA. This feature is what i lacked in C++, but as 
 you know, appetite comes with eating, so i think there's still 
 room for improvement in UDAs.

 The problem is current UDAs can't modify definition they're 
 attached to. The solution is somewhere near Python's 
 decorators, but of course, using compile-time templates or 
 mixins.

 Here's an example:

 template MyAttr(string name, T)
 {

 }

  MyAttr class MyClass
 {
  ... class body
 }

 Which should evaluate to something like:
 class __MyClassTmpThatWillBeRemovedInCompileTime
 {
  ... class body
 }

 mixin(MyAttr!("MyClass", 
 __MyClassTmpThatWillBeRemovedInCompileTime));

 Next, MyAttr can modify the class, rename it, ignore it (in 
 this case MyClass will not be available further), define 
 something else instead of it.
 I could try and modify dmd to support it at least as a 
 prototype, but before, i'd like to know whether such feature 
 was already considered and rejected. Thanx.
Seems you want something similar to AST macros [1]. [1] http://wiki.dlang.org/DIP50 -- /Jacob Carlborg
Mar 17 2014
parent reply "Yuriy" <yuriy.glukhov gmail.com> writes:
That really seems to do the job! However it seems like current 
mixins are going to be somewhat redundant with AST macros?

On Monday, 17 March 2014 at 13:23:55 UTC, Jacob Carlborg wrote:
 Seems you want something similar to AST macros [1].

 [1] http://wiki.dlang.org/DIP50

 --
 /Jacob Carlborg
Mar 17 2014
parent Jacob Carlborg <doob me.com> writes:
On 2014-03-17 15:35, Yuriy wrote:
 That really seems to do the job! However it seems like current mixins
 are going to be somewhat redundant with AST macros?
Yes, unfortunately will most likely never see AST macros in D. -- /Jacob Carlborg
Mar 17 2014
prev sibling parent reply "Dicebot" <public dicebot.lv> writes:
Hello Yuriv,

Currently declarative meta-programming is somewhat special in D 
compared to dynamic languages like python in a sense that all 
language entities are actually immutable. You can use those as a 
base for code generation but can't re-write existing symbols - 
this is a very basic property of the language and I highly doubt 
this will be ever changed (I would have been among first 
protesters, actually).

That means that you need to organize your code differently to 
achieve similar usability in D. Two main patterns I am aware of:

1)
Apply UDA's in context of some compile-time framework and put any 
modifications to be done on calling side while preserving actual 
function / class signatures as-is.

For example, when vibe.d REST interface is annotated with 
 rootPathFromName, it does not actually change anything in 
interface but indicates to route generation comile-time algorithm 
that it should be processed differently. In all other contexts 
interface still can be used as it has no UDA attached.

2)
Use a private symbol as an input to generate actual public one. 
Something like this:

 SomeUDA
private class MyClassImpl
{
     // ...
}

// `generate` being some templated CTFE function that used 
reflection to
// build code of new public class to mixin (with a name "MyClass")
mixin(generate!(MyClassImpl, "MyClass"));

There are several common utilities missing in Phobos to make such 
coding style much easier but will definitely improve in that 
regard ;)

One example of function attribute implementation somewhat similar 
in spirit to Python decorators I have written for vibe.d : 
https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/internal/meta/funcattr.d

I will also be speaking on this topic on upcoming DConf.
Mar 17 2014
parent reply "Yuriy" <yuriy.glukhov gmail.com> writes:
Hello Dicebot,
I get your point. AST macros as they are explained in DIP50 are 
probably too powerful for a safe-by-default language. Also they 
could seduce users to implement custom syntax for cases, where D 
syntax could suffice. However, it's clearly seen from your 
example in vibe.d that using "decorators" expects users to know 
how to explicitly "evaluate" them. Otherwise, your "decorated" 
code could be misused if used "intuitively". Such approach 
effectively leads to at least two places in code, where you need 
to know about the logic of an attribute.

I totally agree that modifying decorators could add another way 
of shooting your foot, but it seems to me that it's benefits are 
worth it. Besides, decorating a definition with an uninstantiated 
template would not break current syntax and current UDA logic. 
Also it could be potentially implemented by lowering, as 
described in my first message. Also, don't we love C++ for it's 
infinite number of ways to shoot your foot? =)
Mar 18 2014
parent "Dicebot" <public dicebot.lv> writes:
On Tuesday, 18 March 2014 at 10:36:31 UTC, Yuriy wrote:
 However, it's clearly seen from your example in vibe.d that 
 using "decorators" expects users to know how to explicitly 
 "evaluate" them. Otherwise, your "decorated" code could be 
 misused if used "intuitively". Such approach effectively leads 
 to at least two places in code, where you need to know about 
 the logic of an attribute.
In vibe.d context it is intentionally designed that way. Same classes can be re-used as is for any other request handling - additional annotations make sense only within REST context. Splitting allows to achieve perfect decoupling here. In case you want to make persistent adjustment, approach (2) is recommended. It can effectively achieve the same result as true decoration with only difference that explicit mixin is required to hint both reader and compiler what is actually happening here. In real project it is up to your personal judgement which approach fits use case better.
 I totally agree that modifying decorators could add another way 
 of shooting your foot, but it seems to me that it's benefits 
 are worth it. Besides, decorating a definition with an 
 uninstantiated template would not break current syntax and 
 current UDA logic. Also it could be potentially implemented by 
 lowering, as described in my first message.
I think it is possible but gain does not seem to be worth complications. On a related notes, I'd also love to see "contained" AST macros, similar to how string mixins are always explicit.
 Also, don't we love C++ for it's infinite number of ways to 
 shoot your foot? =)
Well.. no. Not really :)
Mar 18 2014