DIP60: @nogc attribute

Frustrated via Digitalmars-d digitalmars-d at puremagic.com
Mon Apr 21 10:49:35 PDT 2014


On Monday, 21 April 2014 at 16:45:15 UTC, Jacob Carlborg wrote:
> On Sunday, 20 April 2014 at 14:38:47 UTC, Frustrated wrote:
>
>> How bout this!
>>
>> Why not allow one to define their own attributes from a 
>> generalized subset and then define a few standard ones like 
>> @nogc.
>
> Sounds like you want AST macros. Have a look at this 
> http://wiki.dlang.org/DIP50#Declaration_macros
>
> --
> /Jacob Carlborg

Not quite. AST macros simply transform code. Attributes attach 
meta data to code. While I'm sure there is some overlap they are 
not the same.

Unless AST macros have the ability to arbitrary add additional 
contextual information to meta code then they can't emulate 
attributes.

E.g., Suppose you have D with AST macros but not attributes, how 
can you add them?

In the dip, you have

macro attr (Context context, Declaration decl)
{
     auto attrName = decl.name;
     auto type = decl.type;

     return <[
         private $decl.type _$decl.name;

         $decl.type $decl.name ()
         {
             return _$decl.name;
         }

         $decl.type $decl.name ($decl.type value)
         {
             return _$decl.name = value;
         }
     ]>;
}

class Foo
{
     @attr int bar;
}

but attr is not an attribute. It is an macro. @attr converts the 
"int bar" field into a private setter and getter. This has 
nothing to do with attributes.

(just cause you use the attr word and the @ symbol doesn't make 
it an attribute)


I don't see how you could ever add attributes to D using AST 
macros above unless the definition of an AST macro is modified. 
[Again, assuming D didn't have attributes in the first place]

This does not mean that AST macros could not be used to help 
define the generalized attributes though.


What I am talking about is instead of hard coding attributes in 
the compiler, one abstracts and generalizes the code so that any 
attribute could be added in the future with minimal work.

It would simply require one to add the built in attributes list, 
add the attribute grammar(which is used to reduce compound 
attributes), add any actions that happen when the attribute is 
used in code.

e.g.,

builtin_attributes = {

     {pureness, pure, !pure/impure,
         attr = any(attr, impure) => impure
         attr = all(attr, pure) => pure
     }

     {gc, gc, !gc/nogc,
         attr = any(attr, gc) => gc
         attr = all(attr, nogc) => nogc
     }
     etc... }

notices that pureness and gc have the same grammatical rules. 
Code would be added to handle the pureness and gc attributes when 
they are come across for optimization purposes.

The above syntax is just made up and pretty bad but hopefully not 
too difficult to get the bigger picture.

Every new built in attribute would just have to be added to the 
list above(easy) and code that uses it for whatever purpose would 
be added in the code where it belongs.

User define attributes essentially would make the attributes list 
above dynamic allowing the user to add to it. The compiler would 
only be told how to simplify the attributes using the grammar and 
would do so but would not have any code inserted because there is 
no way for the user to hook into the compiler properly(I suppose 
it could be done if the compiler was written in an oop like way).

In any case, because the compiler knows how to simplify UDA's by 
using the provided grammar it makes UDA's much more powerful. CT 
reflection and AST macros would make them way more powerful. The 
ability to add hooks into the compiler would nearly give the user 
the same power as the compiler writer. Of course, this would 
probably lead to all kinds of compatibility problems in user code.

Basically, as of now, all we can do is define UDA's, we can't 
define how they relate to each other(the grammar) nor what 
happens when the exist(the behavior). There should not be any 
real difference between UDA's and built in attributes(except 
hooking, only because of complexity issues) and having a 
generalized attribute system in the compiler would go a long way 
to bridging the gap.

The main thing to take away from this is that *if* D had such an 
attribute system, the gc/nogc issue would be virtually 
non-existent. It would only take a few minutes to add a UDA 
@gc/@nogc to D in user code. At least a few people would have 
done it, and it's merits could be seen. Then it would be only a 
matter of "copy and pasting" the definition of the attribute to 
the compiler code and it would then become a built in making it 
available for everyone.

At some point optimizations in the compiler could potentially be 
added... just for fun. Not really the point of the attribute but 
having it does provide such possibilities.

Also, with such a system, attributes can propagate from the 
bottom up and inference makes it a lot easier.

E.g., atomic statements could be "marked" with attributes. Blocks 
of statements can be marked but also inherit from the statements 
and blocks they use.

With such a system, one could mark individual assembly 
instructions as, say, @dangerous. If @dangerous was a "bubbling" 
attribute then you could check and see which functions in your 
code was @dangerous, or if your program was @dangerous.

One could do it similar with @allocate. Any primitive thing that 
allocates in D should get the attribute. Then, if @allocate is a 
"bubbling" attribute, you could find out exactly which parts of 
code in your allocates. You could even find out were this happens.

e.g.,

void foo()
{
      auto m = core.stdc.stdlib.malloc(size);
      bar(); // assume bar does not have @allocate attribute(does 
not allocate memory in any way)
}

foo would be marked @allocate since malloc is marked with 
@allocate and @allocate is an inheriting attribute. A utility 
could be written that shows the hierarchy of the program allowing 
you to explore things and you could find foo and see that the 
reason why foo is marked @allocate is because it calls malloc 
which is marked @allocate. (malloc would be explicitly marked 
while foo would be deduced by the compiler for us)

Hopefully it is easy to see that by starting from the bottom and 
with a well defined attribute system the compiler can become more 
powerful by automatically simplifying attributes for us no matter 
how complex the program.












More information about the Digitalmars-d mailing list