www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - More useful fixed-size array literals

reply "bearophile" <bearophileHUGS lycos.com> writes:
Code similar to this is not uncommon. Currently it's refused:


immutable data = [1, 5, 3, 1, 5, 1, 5];
void main()  nogc {
     import std.algorithm: count;
     assert(data.count([1, 5]) == 3);
}


test.d(4,23): Error: array literal in  nogc function main may 
cause GC allocation


The current workaround is not handy when you have conditionals, 
etc:

immutable data = [1, 5, 3, 1, 5, 1, 5];
void main()  nogc {
     import std.algorithm: count;
     immutable static part = [1, 5];
     assert(data.count(part) == 3);
}


A language solution is a literal syntax for fixed-sized arrays 
(here I slice it again because unfortunately count doesn't accept 
fixed-sized arrays):


immutable data = [1, 5, 3, 1, 5, 1, 5];
void main()  nogc {
     import std.algorithm: count;
     assert(data.count([1, 5]s[]) == 3);
}


I remember Kenji is not fond of this []s syntax, for reasons I 
don't remember. Do you think there are other better/different 
solutions?

Bye,
bearophile
May 30 2014
next sibling parent "Meta" <jared771 gmail.com> writes:
On Friday, 30 May 2014 at 22:19:51 UTC, bearophile wrote:
 Code similar to this is not uncommon. Currently it's refused:


 immutable data = [1, 5, 3, 1, 5, 1, 5];
 void main()  nogc {
     import std.algorithm: count;
     assert(data.count([1, 5]) == 3);
 }


 test.d(4,23): Error: array literal in  nogc function main may 
 cause GC allocation


 The current workaround is not handy when you have conditionals, 
 etc:

 immutable data = [1, 5, 3, 1, 5, 1, 5];
 void main()  nogc {
     import std.algorithm: count;
     immutable static part = [1, 5];
     assert(data.count(part) == 3);
 }


 A language solution is a literal syntax for fixed-sized arrays 
 (here I slice it again because unfortunately count doesn't 
 accept fixed-sized arrays):


 immutable data = [1, 5, 3, 1, 5, 1, 5];
 void main()  nogc {
     import std.algorithm: count;
     assert(data.count([1, 5]s[]) == 3);
 }


 I remember Kenji is not fond of this []s syntax, for reasons I 
 don't remember. Do you think there are other better/different 
 solutions?

 Bye,
 bearophile

What about prepending the word static? immutable data = [1, 5, 3, 1, 5, 1, 5]; void main() nogc { import std.algorithm: count; assert(data.count(static[1, 5]) == 3); } Or variadic template arguments. Aren't they allocated on the stack like static arrays? immutable data = [1, 5, 3, 1, 5, 1, 5]; void main() nogc { import std.algorithm: count; //Assume count has a variadic template implementation assert(data.count(1, 5) == 3); }
May 30 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Meta:

 What about prepending the word static?

 immutable data = [1, 5, 3, 1, 5, 1, 5];
 void main()  nogc {
     import std.algorithm: count;
     assert(data.count(static[1, 5]) == 3);
 }

This is about the same as appending the char 's'.
 Or variadic template arguments. Aren't they allocated on the 
 stack like static arrays?

 immutable data = [1, 5, 3, 1, 5, 1, 5];
 void main()  nogc {
     import std.algorithm: count;
     //Assume count has a variadic template implementation
     assert(data.count(1, 5) == 3);
 }

Currently they are allocated on the stack. But "count" doesn't work like that. And I think this feature of D is bug-prone, and in bugzilla I've asked to change it (allocating on the heap on default). Bye, bearophile
May 30 2014
prev sibling next sibling parent "Mason McGill" <mmcgill caltech.edu> writes:
On Friday, 30 May 2014 at 22:19:51 UTC, bearophile wrote:
 A language solution is a literal syntax for fixed-sized arrays 
 (here I slice it again because unfortunately count doesn't 
 accept fixed-sized arrays):


 immutable data = [1, 5, 3, 1, 5, 1, 5];
 void main()  nogc {
     import std.algorithm: count;
     assert(data.count([1, 5]s[]) == 3);
 }

I would use this often. It's always seemed strange to me that static arrays are one of the few built-in data structures that don't have a dedicated literal form. `[1, 2, 3]s` nicely parallels the syntax for string and number literals.
May 30 2014
prev sibling next sibling parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
Am 31.05.2014 00:19, schrieb bearophile:
 Code similar to this is not uncommon. Currently it's refused:


 immutable data = [1, 5, 3, 1, 5, 1, 5];
 void main()  nogc {
      import std.algorithm: count;
      assert(data.count([1, 5]) == 3);
 }


 test.d(4,23): Error: array literal in  nogc function main may cause GC
 allocation


 The current workaround is not handy when you have conditionals, etc:

 immutable data = [1, 5, 3, 1, 5, 1, 5];
 void main()  nogc {
      import std.algorithm: count;
      immutable static part = [1, 5];
      assert(data.count(part) == 3);
 }


 A language solution is a literal syntax for fixed-sized arrays (here I
 slice it again because unfortunately count doesn't accept fixed-sized
 arrays):


 immutable data = [1, 5, 3, 1, 5, 1, 5];
 void main()  nogc {
      import std.algorithm: count;
      assert(data.count([1, 5]s[]) == 3);
 }


 I remember Kenji is not fond of this []s syntax, for reasons I don't
 remember. Do you think there are other better/different solutions?

 Bye,
 bearophile

give "scope" a meaning for function arguments other then lambdas E.g: size_t count(scope int[] heystack, scope int[] needle); Now the compiler can allocate the literal [1, 5] on the stack without any special syntax because it knows that the array literal will not be escaped. Kind Regards Benjamin Thaut
May 30 2014
parent Benjamin Thaut <code benjamin-thaut.de> writes:
Am 31.05.2014 11:08, schrieb bearophile:
 int foo(scope int[] items)  nogc {
     return foo.sum;
 }

That was: return items.sum; Bye, bearophile

Well obviously the std.algorithm sum would also be annoted with scope. Because it doesn't escape it either. I don't see the problem here. And in case you really want to escape it, you need to .dup it. A additional advantage of my solution is, that the compiler can prove it to be safe. Your solution does not allow that. Kind Regards Benjamin Thaut
May 31 2014
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 I remember Kenji is not fond of this []s syntax, for reasons I 
 don't remember. Do you think there are other better/different 
 solutions?

 Bye,
 bearophile

Read it on my closed Pull Request: https://github.com/D-Programming-Language/dmd/pull/2952 Another attempt was also closed: https://github.com/D-Programming-Language/dmd/pull/2958
May 31 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Benjamin Thaut:

 give "scope" a meaning for function arguments other then 
 lambdas E.g:

 size_t count(scope int[] heystack, scope int[] needle);

 Now the compiler can allocate the literal [1, 5] on the stack 
 without any special syntax because it knows that the array 
 literal will not be escaped.

With your suggestion this code should be accepted: int foo(scope int[] items) nogc { int total = 0; foreach (immutable x; items) total += x; return total; } void main() nogc { assert(foo([1, 5, 3, 1, 5, 1, 5]) == 21); } While this can't be accepted because 'items' escapes the body of 'foo', so 'scope' forbids some valid code: import std.algorithm: sum; int foo(scope int[] items) nogc { return foo.sum; } void main() nogc { assert(foo([1, 5, 3, 1, 5, 1, 5]) == 21); } The []s syntax moves the control to the calling point, allowing more valid code to compile: import std.algorithm: sum; int foo(int[] items) nogc { return foo.sum; } void main() nogc { assert(foo([1, 5, 3, 1, 5, 1, 5]s) == 21); } A disadvantage of the []s syntax is that it's less safe than scope: int[] global; void foo() nogc { bar([1, 5, 3, 1, 5, 1, 5]s); } void bar(int[] b) nogc { global = b; } void main() { import std.stdio; foo(); writeln(global); } But that usage of []s is not much worse than this currently accepted code, the difference is that the []s syntax makes this problem a bit less visible: int[] global; void foo() nogc { int[7] a = [1, 5, 3, 1, 5, 1, 5]; bar(a); // Implicit slicing. } void bar(int[] b) nogc { global = b; } void main() { import std.stdio; foo(); writeln(global); } (I think Jonathan M Davis suggested to disallow such implicit slicing, and require a "bar(a[]);".) A possible way to increase the number of functions allowed by 'scope' is to allow a reference to escape if it goes into another 'scope': int sum(scope int[] items) nogc { int total = 0; foreach (immutable x; items) total += x; return total; } int foo(scope int[] items) nogc { return sum(items); // Allowed. } void main() nogc { assert(foo([1, 5, 3, 1, 5, 1, 5]) == 21); // Allowed. } (The problem with Scott Meyers' suggestion in the "The Last Thing D Needs" keynote is that to design a language/library feature that takes in account every other language/library part, you need a mind significantly larger than the average human one :-) ). Bye, bearophile
May 31 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
 int foo(scope int[] items)  nogc {
     return foo.sum;
 }

That was: return items.sum; Bye, bearophile
May 31 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Benjamin Thaut:

 Well obviously the std.algorithm sum would also be annoted with 
 scope. Because it doesn't escape it either. I don't see the 
 problem here. And in case you really want to escape it, you 
 need to .dup it.

 A additional advantage of my solution is, that the compiler can 
 prove it to be  safe. Your solution does not allow that.

You can see that the contents of this answer of yours are a strict subset of the contents of my last post :-) A problem with that use of "scope" to solve this problem is that such feature interacts with several other things (like ownership), so it's a complex topic, so nearly everyone is afraid of touching and implementing it, so nothing will happen. This phenomenon has happened even for more contained features the "old" (prestate) of contract programming, for built-in D tuple syntax, etc. And we keep having a language with holes, that lacks such basic features. This means that sometimes designing a language in a less coherent way (in Scott Meyers' words) is better than having a language that lacks certain basic features. I hope Walter or others will figure out this topic of ownership, etc. Bye, bearophile
May 31 2014
prev sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:

 Another attempt was also closed:
 https://github.com/D-Programming-Language/dmd/pull/2958

There is a good hope: https://github.com/D-Programming-Language/dmd/pull/3615 Bye, bearophile
Jun 02 2014