www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - what are the rules for nogc and safe attributes inference?

reply ikod <geller.garry gmail.com> writes:
Hello,

what are the rules for  nogc inference? It looks like sometimes 
compiler can infer  nogc, but not in this simplest case:

int x()
{
     return 1;
}
void main()  nogc
{
     x();
}

Thanks!
Nov 15 2018
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 15 November 2018 at 21:00:48 UTC, ikod wrote:
 what are the rules for  nogc inference?
It attempts it if and only if it is a template.
Nov 15 2018
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 11/15/18 4:09 PM, Adam D. Ruppe wrote:
 On Thursday, 15 November 2018 at 21:00:48 UTC, ikod wrote:
 what are the rules for  nogc inference?
It attempts it if and only if it is a template.
Well, the general "rule" is, if it's code that must be available to the compiler when it's called, then it will be inferred. Examples of code that must be processed every time it's used: 1. Template functions 2. auto-returning functions 3. functions inside templates (like member functions of a templated struct) 4. Inner functions There may be others I didn't think of. Everything else must be manually attributed. The reasoning is that the function may be stubbed in a .di file, and in that case, attribute inference wouldn't be possible. -Steve
Nov 15 2018
next sibling parent reply ikod <geller.garry gmail.com> writes:
On Thursday, 15 November 2018 at 21:55:18 UTC, Steven 
Schveighoffer wrote:
 On 11/15/18 4:09 PM, Adam D. Ruppe wrote:
 On Thursday, 15 November 2018 at 21:00:48 UTC, ikod wrote:
 what are the rules for  nogc inference?
It attempts it if and only if it is a template.
Well, the general "rule" is, if it's code that must be available to the compiler when it's called, then it will be inferred. Examples of code that must be processed every time it's used: 1. Template functions 2. auto-returning functions 3. functions inside templates (like member functions of a templated struct) 4. Inner functions There may be others I didn't think of. Everything else must be manually attributed. The reasoning is that the function may be stubbed in a .di file, and in that case, attribute inference wouldn't be possible. -Steve
Thanks for clarifications, Adam and Steven! My problem is next code: ================================================= import std.traits; T library_func(T)(/*lazy*/ T i) { // this fuction can be nogc or not depending on T properties static if (isArray!T) { return i ~ i; } else { return i; } } void user_function_nogc() nogc { int x = 1; library_func(x+1); } void user_function_gc() { library_func([1]); } void main() { } ===================================================== This code compiles as long as `lazy` is commented out. But I'd like to have both lazy parameter and nogc inferrence for `library_func` so that user is not locked to code nogc or not.
Nov 16 2018
parent reply Alex <sascha.orlov gmail.com> writes:
On Friday, 16 November 2018 at 10:25:26 UTC, ikod wrote:
 On Thursday, 15 November 2018 at 21:55:18 UTC, Steven 
 Schveighoffer wrote:
 On 11/15/18 4:09 PM, Adam D. Ruppe wrote:
 On Thursday, 15 November 2018 at 21:00:48 UTC, ikod wrote:
 what are the rules for  nogc inference?
It attempts it if and only if it is a template.
Well, the general "rule" is, if it's code that must be available to the compiler when it's called, then it will be inferred. Examples of code that must be processed every time it's used: 1. Template functions 2. auto-returning functions 3. functions inside templates (like member functions of a templated struct) 4. Inner functions There may be others I didn't think of. Everything else must be manually attributed. The reasoning is that the function may be stubbed in a .di file, and in that case, attribute inference wouldn't be possible. -Steve
Thanks for clarifications, Adam and Steven! My problem is next code: ================================================= import std.traits; T library_func(T)(/*lazy*/ T i) { // this fuction can be nogc or not depending on T properties static if (isArray!T) { return i ~ i; } else { return i; } } void user_function_nogc() nogc { int x = 1; library_func(x+1); } void user_function_gc() { library_func([1]); } void main() { } ===================================================== This code compiles as long as `lazy` is commented out. But I'd like to have both lazy parameter and nogc inferrence for `library_func` so that user is not locked to code nogc or not.
Aha, aha... Interesting! I had a similar problem with passing a delegate. And it was solved: https://forum.dlang.org/thread/erznqknpyxzxqivawnix forum.dlang.org For your problem, there is a bug report: https://forum.dlang.org/post/wedwfooqdxbwxttpmzim forum.dlang.org https://issues.dlang.org/show_bug.cgi?id=12664 https://issues.dlang.org/show_bug.cgi?id=12647
Nov 16 2018
parent ikod <geller.garry gmail.com> writes:
On Friday, 16 November 2018 at 12:12:12 UTC, Alex wrote:
 =====================================================
 This code compiles as long as `lazy` is commented out. But I'd 
 like to have
 both lazy parameter and  nogc inferrence for `library_func` so 
 that user is not locked to code  nogc or not.
Aha, aha... Interesting! I had a similar problem with passing a delegate. And it was solved: https://forum.dlang.org/thread/erznqknpyxzxqivawnix forum.dlang.org For your problem, there is a bug report: https://forum.dlang.org/post/wedwfooqdxbwxttpmzim forum.dlang.org https://issues.dlang.org/show_bug.cgi?id=12664 https://issues.dlang.org/show_bug.cgi?id=12647
Thanks for these links. And yes, I have workaround with handmade delegate. It compiles and it is lazy, but also ugly. import std.traits; T library_func(T)(/*not lazy*/ T i) if (!isCallable!T) { return i; } ReturnType!T library_func(T)(/*lazy*/ T i) if (isCallable!T) { return i(); } void user_function_nogc() nogc { int x = 1; library_func(x+1); } void user_function_gc() { library_func(()=>[1]); } void main() { }
Nov 16 2018
prev sibling parent reply ikod <geller.garry gmail.com> writes:
On Thursday, 15 November 2018 at 21:55:18 UTC, Steven 
Schveighoffer wrote:
 On 11/15/18 4:09 PM, Adam D. Ruppe wrote:
 On Thursday, 15 November 2018 at 21:00:48 UTC, ikod wrote:
 what are the rules for  nogc inference?
It attempts it if and only if it is a template.
Well, the general "rule" is, if it's code that must be available to the compiler when it's called, then it will be inferred. Examples of code that must be processed every time it's used: 1. Template functions 2. auto-returning functions 3. functions inside templates (like member functions of a templated struct) 4. Inner functions There may be others I didn't think of. Everything else must be manually attributed. The reasoning is that the function may be stubbed in a .di file, and in that case, attribute inference wouldn't be possible. -Steve
Hello, Steve! I can't find the reason why nogc/nothrow can't be inferred in this case: class S(K,V) { auto get/*()*/(K a) { return 0; } } void main() nogc nothrow { S!(int, string) sia; auto v = sia.get(1); } But everything is ok if you uncomment parentheses after get. get is already a member of templated class, what can be wrong with this code? Thanks!
Nov 30 2018
parent reply Neia Neutuladh <neia ikeran.org> writes:
On Fri, 30 Nov 2018 20:41:03 +0000, ikod wrote:
 I can't find the reason why nogc/nothrow can't be inferred in this case:
 
 class S(K,V)
 {
      auto get/*()*/(K a) {
          return 0;
      }
 }
 void main()  nogc nothrow {
      S!(int, string) sia;
      auto v = sia.get(1);
 }
class Nefarious : S!(int, string) { override int get(int a) { // Whoops, I used the GC return new char[a].length; } } The compiler can't prove that a variable of type S!(int, string) will not be of type Nefarious, which uses the GC, so it can't infer nogc for S.get. However, if you make the function final, then the compiler can infer it to be pure nothrow nogc safe. Or if you use a struct instead of a class, structs don't do inheritance, so the compiler can infer attributes without worrying about nefarious inheritance.
 But everything is ok if you uncomment parentheses after get.
Templated functions are implicitly final.
Nov 30 2018
parent reply ikod <geller.garry gmail.com> writes:
On Friday, 30 November 2018 at 21:03:06 UTC, Neia Neutuladh wrote:
 On Fri, 30 Nov 2018 20:41:03 +0000, ikod wrote:
 I can't find the reason why nogc/nothrow can't be inferred in 
 this case:
 
 class S(K,V)
 {
      auto get/*()*/(K a) {
          return 0;
      }
 }
 void main()  nogc nothrow {
      S!(int, string) sia;
      auto v = sia.get(1);
 }
class Nefarious : S!(int, string) { override int get(int a) { // Whoops, I used the GC return new char[a].length; } } The compiler can't prove that a variable of type S!(int, string) will not be of type Nefarious, which uses the GC, so it can't infer nogc for S.get. However, if you make the function final, then the compiler can infer it to be pure nothrow nogc safe. Or if you use a struct instead of a class, structs don't do inheritance, so the compiler can infer attributes without worrying about nefarious inheritance.
 But everything is ok if you uncomment parentheses after get.
Templated functions are implicitly final.
Thanks for explanation, got it. My case is actually interface I(K,V) { int get()(K); } class S(K,V) : I!(K, V) { int v; int get()(K a) { return v; } } void main() nothrow { S!(int, string) s = new S!(int, string); s.get(1); } My goal is to allow compiler to infer all properties of s.get without adding nothrow/nogc anywhere. And these templated functions is only way it works for me. Is it ok? Or there is better solution? Thanks!
Nov 30 2018
parent Neia Neutuladh <neia ikeran.org> writes:
On Fri, 30 Nov 2018 22:10:11 +0000, ikod wrote:
 Thanks for explanation, got it.
 
 My case is actually
 
 interface I(K,V)
 {
      int get()(K);
 }
Interface functions must be abstract. Templated functions are implicitly final. Final things can't be abstract. If there's something about types K and V that determine whether you should be able to use the GC or not, you'll have to encode that explicitly.
Nov 30 2018