Thread overview
Idea: Context sensitive attribute functions.
Jun 19, 2018
12345swordy
Jun 19, 2018
Dennis
Jun 19, 2018
Dennis
Jun 19, 2018
Jonathan M Davis
Jun 19, 2018
Dennis
Jun 19, 2018
Jonathan M Davis
Jun 20, 2018
12345swordy
June 19, 2018
Pseudocode:
void example()
{
static if(Context = @nogc)
{
//nogc implementation
}
else
{
//gc implementation
}
}

This is useful as it eliminate the need to create multiple functions for each possible system attribute hence reducing redundant code. There are advantages of having a gc/unsafe/throw code. Why not use them if given the opportunity based on its context?

- Alex
June 19, 2018
On Tuesday, 19 June 2018 at 19:03:44 UTC, 12345swordy wrote:
> Why not use them if given the opportunity based on its context?

You can do that if you want
```
import std.stdio;
import core.stdc.stdio;

void main() @nogc {
    int a = 8;
    static if (__traits(compiles, new int(0))) {
        writefln("writeln %d", a);
    } else {
        printf("printf %d", a);
    }
}
```
June 19, 2018
On Tuesday, 19 June 2018 at 21:06:16 UTC, Dennis wrote:
> On Tuesday, 19 June 2018 at 19:03:44 UTC, 12345swordy wrote:
>> Why not use them if given the opportunity based on its context?
>
> You can do that if you want

Although it doesn't seem to work in attribute interference of templates.

```
void main() @nogc {
    example();
}

void example()() {
    int a = 8;
    static if (__traits(compiles, new int(0))) {
        writefln("writeln %d", a);
    } else {
        printf("printf %d", a);
    }
}
```

onlineapp.d(5): Error: @nogc function D main cannot call non-@nogc function onlineapp.example!().example

Maybe there's some workaround?
June 19, 2018
On Tuesday, June 19, 2018 21:11:10 Dennis via Digitalmars-d wrote:
> On Tuesday, 19 June 2018 at 21:06:16 UTC, Dennis wrote:
> > On Tuesday, 19 June 2018 at 19:03:44 UTC, 12345swordy wrote:
> >> Why not use them if given the opportunity based on its context?
> >
> > You can do that if you want
>
> Although it doesn't seem to work in attribute interference of templates.
>
> ```
> void main() @nogc {
>      example();
> }
>
> void example()() {
>      int a = 8;
>      static if (__traits(compiles, new int(0))) {
>          writefln("writeln %d", a);
>      } else {
>          printf("printf %d", a);
>      }
> }
> ```
>
> onlineapp.d(5): Error: @nogc function D main cannot call
> non-@nogc function onlineapp.example!().example
>
> Maybe there's some workaround?

Whether a function is @nogc has nothing to do with where it's called from. It has to do with what it calls. As such, new int(0) compiles just fine inside of your example function, and that branch is compiled in, making it so that the function is not @nogc. I am not aware of any way to make a function's attributes depend on what calls it. The closest would be if you changed what it did based on its template arguments - which would mean doing something like passing a bool or flag indicating whether the function should be compiled as @nogc or not. I don't think that it's possible to have a function be compiled differently based on where it's called from. Attribute inference is all about inferring the attributes of the templated function based on its implementation, not adjusting its implementation based on where it's used.

- Jonathan M Davis

June 19, 2018
On Tuesday, 19 June 2018 at 21:38:14 UTC, Jonathan M Davis wrote:
> Attribute inference is all about inferring the attributes of the templated function based on its implementation, not adjusting its implementation based on where it's used.

Indeed, I realised that the same template instantiation can't possibly have both a @nogc and @gc version, so there has to be a template parameter. You can automatically set one however:


```
void main() @nogc {
    example();
}

void example(string callee = __FUNCTION__)() {

    int a = 8;
    static if (isNoGc!callee) {
        printf("printf %d", a);
    } else {
        writefln("writeln %d", a);
    }
}

bool isNoGc(string functionName)() {
    import std.algorithm;
    mixin(`return [__traits(getFunctionAttributes, `~functionName~`)].canFind("@nogc");`);
}
```

This seems to work. I'm not sure how robust it is though. You might need an extra `mixin("import "~functionName~";");` in `isNoGc` when it's called from other modules (if that helps at all).
June 19, 2018
On Tuesday, June 19, 2018 22:22:23 Dennis via Digitalmars-d wrote:
> On Tuesday, 19 June 2018 at 21:38:14 UTC, Jonathan M Davis wrote:
> > Attribute inference is all about inferring the attributes of the templated function based on its implementation, not adjusting its implementation based on where it's used.
>
> Indeed, I realised that the same template instantiation can't possibly have both a @nogc and @gc version, so there has to be a template parameter. You can automatically set one however:
>
>
> ```
> void main() @nogc {
>      example();
> }
>
> void example(string callee = __FUNCTION__)() {
>
>      int a = 8;
>      static if (isNoGc!callee) {
>          printf("printf %d", a);
>      } else {
>          writefln("writeln %d", a);
>      }
> }
>
> bool isNoGc(string functionName)() {
>      import std.algorithm;
>      mixin(`return [__traits(getFunctionAttributes,
> `~functionName~`)].canFind("@nogc");`);
> }
> ```
>
> This seems to work. I'm not sure how robust it is though. You
> might need an extra `mixin("import "~functionName~";");` in
> `isNoGc` when it's called from other modules (if that helps at
> all).

Hmm. That's clever, but that approach would not work very well with function overloads. Also, it falls apart on some level if the caller is a template function that relies on attribute inference to be @nogc. In such cases, the caller would be infered as not being @nogc, and example would be compiled with the GC version. In addition, even if it all worked perfectly, it would mean compiling a different instantation of the function for every function that calls it, which seems likely to cause an awful lot of bloat. It's not as bad as using __FILE__ and __LINE__ as template arguments, but it's close.

Another problem here is that as long as we can't introspect on private members of other modules (which really should be fixed), this would likely fail to compile when the caller is private and in another module. But hopefully, that's just a temporary issue. Making it deal with overloads correctly is likely a far bigger issue long term.

- Jonathan M Davis

June 20, 2018
On Tuesday, 19 June 2018 at 21:06:16 UTC, Dennis wrote:
> On Tuesday, 19 June 2018 at 19:03:44 UTC, 12345swordy wrote:
>> Why not use them if given the opportunity based on its context?
>
> You can do that if you want
> ```
> import std.stdio;
> import core.stdc.stdio;
>
> void main() @nogc {
>     int a = 8;
>     static if (__traits(compiles, new int(0))) {
>         writefln("writeln %d", a);
>     } else {
>         printf("printf %d", a);
>     }
> }
> ```

No, it is not the same. You are testing one of the rules that is defined by the attribute, you are not testing the attribute itself that is derived by the  context that you are in. You code can't take into account of custom attributes.

Alexander