www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Question about nogc

reply "Dominikus Dittes Scherkl" writes:
Did I understand correct that a function can only be  nogc if 
also all functions that it calls are  nogc too (and of course it 
doesn't use the GC itself)?

If so, should this be possible:

string foo()
{
    // use GC to allocate some string
}

bar  nogc
{
    mixin(foo());
}

Because, bar() didn't really call foo() but instead foo() is 
evaluated during compile time and it's result is now part of the 
code, right?
May 20 2014
next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 20 May 2014 at 12:25:11 UTC, Dominikus Dittes Scherkl 
wrote:
 Did I understand correct that a function can only be  nogc if 
 also all functions that it calls are  nogc too (and of course 
 it doesn't use the GC itself)?

 If so, should this be possible:

 string foo()
 {
    // use GC to allocate some string
 }

 bar  nogc
 {
    mixin(foo());
 }

 Because, bar() didn't really call foo() but instead foo() is 
 evaluated during compile time and it's result is now part of 
 the code, right?
Right. It's the same mechanics you'd get from pure/nothrow and safe+ trusted
May 20 2014
prev sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Tuesday, 20 May 2014 at 12:25:11 UTC, Dominikus Dittes Scherkl 
wrote:
 Did I understand correct that a function can only be  nogc if 
 also all functions that it calls are  nogc too (and of course 
 it doesn't use the GC itself)?

 If so, should this be possible:

 string foo()
 {
    // use GC to allocate some string
 }

 bar  nogc
 {
    mixin(foo());
 }

 Because, bar() didn't really call foo() but instead foo() is 
 evaluated during compile time and it's result is now part of 
 the code, right?
Yes, that should be allowed.
May 20 2014
parent reply "Dominikus Dittes Scherkl" writes:
On Tuesday, 20 May 2014 at 17:14:31 UTC, John Colvin wrote:
 On Tuesday, 20 May 2014 at 12:25:11 UTC, Dominikus Dittes 
 Scherkl wrote:
 Did I understand correct that a function can only be  nogc if 
 also all functions that it calls are  nogc too (and of course 
 it doesn't use the GC itself)?

 If so, should this be possible:

 string foo()
 {
   // use GC to allocate some string
 }

 bar  nogc
 {
   mixin(foo());
 }

 Because, bar() didn't really call foo() but instead foo() is 
 evaluated during compile time and it's result is now part of 
 the code, right?
Yes, that should be allowed.
Thanks. This is nice to know, because I will use this a lot in the future: /// create a fixed size array with the given name and with *max* entries /// of immutable values of the same type as the return value of the /// given function. /// it contains the values of that function in the range [0..max]. string makeLookupTable(alias fn, uint max=255)(string name) pure safe if(is(typeof(fn(max)))) { string table = "immutable " ~ to!string(typeof(fn(max))) ~ "[" ~ to!string(max+1) ~ "] " ~ name ~"= [ "; foreach(i; 0..max) table ~= to!string(fn(i) ~ ", "; return table ~ to!string(fn(max) ~" ]"; }
May 20 2014
parent reply "anonymous" <anonymous example.com> writes:
On Tuesday, 20 May 2014 at 20:15:09 UTC, Dominikus Dittes Scherkl
wrote:
 /// create a fixed size array with the given name and with 
 *max* entries
max + 1 entries
 /// of immutable values of the same type as the return value of 
 the
 /// given function.
 /// it contains the values of that function in the range 
 [0..max].
 string makeLookupTable(alias fn, uint max=255)(string name) 
 pure  safe if(is(typeof(fn(max))))
 {
    string table = "immutable " ~ to!string(typeof(fn(max))) ~ 
 "[" ~ to!string(max+1) ~ "] " ~ name ~"= [ ";
    foreach(i; 0..max) table ~= to!string(fn(i) ~ ", ";
    return table ~ to!string(fn(max) ~" ]";
 }
Couldn't resist purging that of the string fiddling: private template staticIota(uint n) { import std.typetuple: TypeTuple; static if(n == 0) alias staticIota = TypeTuple!(); else alias staticIota = TypeTuple!(.staticIota!(n - 1), n - 1); } template lookupTable(alias fn, uint max = 255) { import std.traits: ReturnType; import std.typetuple: staticMap; static assert(max < uint.max); enum length = max + 1; enum ctfn(uint x) = fn(x); alias elements = staticMap!(ctfn, staticIota!length); enum ReturnType!fn[length] lookupTable = [elements]; } void main() { char f(uint x) pure safe {return x == 42 ? '!' : '.';} static immutable t = lookupTable!f; static assert(is(typeof(t) == immutable char[256])); assert(t[42] == '!'); }
May 20 2014
next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 20 May 2014 at 21:04:37 UTC, anonymous wrote:
 On Tuesday, 20 May 2014 at 20:15:09 UTC, Dominikus Dittes 
 Scherkl
 wrote:
 /// create a fixed size array with the given name and with 
 *max* entries
max + 1 entries
 /// of immutable values of the same type as the return value 
 of the
 /// given function.
 /// it contains the values of that function in the range 
 [0..max].
 string makeLookupTable(alias fn, uint max=255)(string name) 
 pure  safe if(is(typeof(fn(max))))
 {
   string table = "immutable " ~ to!string(typeof(fn(max))) ~ 
 "[" ~ to!string(max+1) ~ "] " ~ name ~"= [ ";
   foreach(i; 0..max) table ~= to!string(fn(i) ~ ", ";
   return table ~ to!string(fn(max) ~" ]";
 }
Couldn't resist purging that of the string fiddling: ... enum ReturnType!fn[length] lookupTable = [elements];
Depending on what the usecase is, you might want to change that to static immutable instead: static immutable ReturnType!fn[length] lookupTable = [elements]; Remember that when using an enum, the compiler will create a *new* variable on every use. While the compiler can sometimes avoid actually allocating, it may also insert some object code bloat to do so.
May 20 2014
parent "anonymous" <anonymous example.com> writes:
On Tuesday, 20 May 2014 at 21:16:26 UTC, monarch_dodra wrote:
     enum ReturnType!fn[length] lookupTable = [elements];
Depending on what the usecase is, you might want to change that to static immutable instead: static immutable ReturnType!fn[length] lookupTable = [elements]; Remember that when using an enum, the compiler will create a *new* variable on every use. While the compiler can sometimes avoid actually allocating, it may also insert some object code bloat to do so.
That's the "return" line of a template. In the usage example in main() it's static immutable.
May 20 2014
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 05/20/2014 11:04 PM, anonymous wrote:
 On Tuesday, 20 May 2014 at 20:15:09 UTC, Dominikus Dittes Scherkl
 wrote:
 /// create a fixed size array with the given name and with *max* entries
max + 1 entries
 /// of immutable values of the same type as the return value of the
 /// given function.
 /// it contains the values of that function in the range [0..max].
 string makeLookupTable(alias fn, uint max=255)(string name) pure  safe
 if(is(typeof(fn(max))))
 {
    string table = "immutable " ~ to!string(typeof(fn(max))) ~ "[" ~
 to!string(max+1) ~ "] " ~ name ~"= [ ";
    foreach(i; 0..max) table ~= to!string(fn(i) ~ ", ";
    return table ~ to!string(fn(max) ~" ]";
 }
Couldn't resist purging that of the string fiddling: private template staticIota(uint n) { import std.typetuple: TypeTuple; static if(n == 0) alias staticIota = TypeTuple!(); else alias staticIota = TypeTuple!(.staticIota!(n - 1), n - 1); } template lookupTable(alias fn, uint max = 255) { import std.traits: ReturnType; import std.typetuple: staticMap; static assert(max < uint.max); enum length = max + 1; enum ctfn(uint x) = fn(x); alias elements = staticMap!(ctfn, staticIota!length); enum ReturnType!fn[length] lookupTable = [elements]; } ...
Wtf. Is this really the point you are trying to make? :o) This achieves the same: template lookupTable(alias fn,uint max=255){ static assert(max<uint.max); enum ReturnType!fn[max+1] lookupTable=iota(0,max+1).map!fn.array; }
 void main()
 {
       char f(uint x) pure  safe {return x == 42 ? '!' : '.';}
       static immutable t = lookupTable!f;
       static assert(is(typeof(t) == immutable char[256]));
       assert(t[42] == '!');
 }
May 20 2014
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 05/20/2014 11:48 PM, Timon Gehr wrote:
 This achieves the same:

 template lookupTable(alias fn,uint max=255){
      static assert(max<uint.max);
      enum ReturnType!fn[max+1] lookupTable=iota(0,max+1).map!fn.array;
 }
(Though I'd never actually do template argument checking in a static assert within the template body.)
May 20 2014
prev sibling parent "anonymous" <anonymous example.com> writes:
On Tuesday, 20 May 2014 at 21:48:08 UTC, Timon Gehr wrote:
 Wtf. Is this really the point you are trying to make? :o)

 This achieves the same:

 template lookupTable(alias fn,uint max=255){
     static assert(max<uint.max);
     enum ReturnType!fn[max+1] 
 lookupTable=iota(0,max+1).map!fn.array;
 }
Ha! That's ... much better. I wasn't trying to make any point, though.
May 20 2014