www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - T.init for static arrays?

reply Walter Bright <newshound1 digitalmars.com> writes:
Currently, given an array:

    alias T[3] A;
    A a;

the default initializer for A, A.init, is T.init. It is done this way 
for memory efficiency, as:

    a = A.init;

doesn't need to create an array for the rvalue. But it does cause 
generic programming problems, especially with the advent of static 
arrays now being passed by value rather than by ref.

So, I propose changing A.init from being T.init to being [T.init, 
T.init, T.init].

What do you think?
Mar 13 2010
next sibling parent grauzone <none example.net> writes:
Walter Bright wrote:
 Currently, given an array:
 
    alias T[3] A;
    A a;
 
 the default initializer for A, A.init, is T.init. It is done this way 
 for memory efficiency, as:
 
    a = A.init;
 
 doesn't need to create an array for the rvalue. But it does cause 
 generic programming problems, especially with the advent of static 
 arrays now being passed by value rather than by ref.
 
 So, I propose changing A.init from being T.init to being [T.init, 
 T.init, T.init].
 
 What do you think?
This assert should never fail: T x; assert(x is T.init); (Right now it fails for floats because of NaN - can we fix this too? "is" should always do byte comparisons.)
Mar 13 2010
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/13/2010 02:13 PM, Walter Bright wrote:
 Currently, given an array:

 alias T[3] A;
 A a;

 the default initializer for A, A.init, is T.init. It is done this way
 for memory efficiency, as:

 a = A.init;

 doesn't need to create an array for the rvalue. But it does cause
 generic programming problems, especially with the advent of static
 arrays now being passed by value rather than by ref.

 So, I propose changing A.init from being T.init to being [T.init,
 T.init, T.init].

 What do you think?
The irregularity of .init for arrays has been a huge source of problems. I'm very glad you're looking into fixing it. My understanding is that you propose to transform A.init into a literal with as many elements as the length of the array. That has a an issue. Currently array literals default to T[], not T[N]. So this would do the unexpected: alias int[3] A; A a; auto b = A.init; assert(is(typeof(b) == int[]); // pass I was thinking of rewriting (T[N]).init as: { T[N] result; return result; }() i.e. an rvalue of type T[N]. The lambda should be CTFE-able and does not occupy static storage because it creates the temporary on the stack (well, for large arrays the compiler would be free to resort to dynamic allocation). Your solution works if you rewrite (T[N]).init as: (cast(T[N]) [ T.init, T.init, T.init, ... ]) Andrei
Mar 13 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sat, Mar 13, 2010 at 21:13, Walter Bright <newshound1 digitalmars.com>wrote:

 Currently, given an array:

   alias T[3] A;
   A a;

 the default initializer for A, A.init, is T.init. It is done this way for
 memory efficiency, as:

   a = A.init;

 doesn't need to create an array for the rvalue. But it does cause generic
 programming problems, especially with the advent of static arrays now being
 passed by value rather than by ref.

 So, I propose changing A.init from being T.init to being [T.init, T.init,
 T.init].

 What do you think?
That's bug 3826 http://d.puremagic.com/issues/show_bug.cgi?id=3826 I'm all for A.init being [T.init (n times)], as it indeed broke some of my code, so thank you for the suggestion Walter. I was very surprised to see that A.init was T.init. Andrei:
My understanding is that you propose to transform A.init into a literal
with as many elements
as the length of the array. That has a an issue.
Currently array literals default to T[], not T[N].
Ah, yes.
So this would do the unexpected:
alias int[3] A;
A a;
auto b =  A.init;
assert(is(typeof(b) == int[]); // pass
Currently, this does something as unexpected (at least for me): assert( !is (typeof(b) == typeof(a))); // b is an int, a is a int[3] In parallel to what grauzone said, I think this assert should never fail: T x; assert(is(typeof(x) == typeof(T.init)); But then I only use small-size static arrays, as parameters in templates. By small, I mean less than a dozen elements. Other using bigger arrays may shout at this change... Philippe
Mar 13 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:
 What do you think?
Thank you for considering this problem :-) I have posted a request for this few years ago, explaining why it's important for generic code. In my dlibs1 (for D1) have had to add this Init!() to avoid special-casing many of my functions: ReturnType!({T result; return _recordinit(result);}) Init(T)() { T result; return _recordinit(result); } struct _Recordinit(T) { T init; } _Recordinit!(T) _recordinit(T)(T args) { return _Recordinit!(T)(args); } And recently I have added this bug report: http://d.puremagic.com/issues/show_bug.cgi?id=3826 So I think it's useful to fix this.
 It is done this way for memory efficiency, as:
    a = A.init;
 doesn't need to create an array for the rvalue.
It's the first I see an explanation of why it's done this way. The following examples are written in the page about arrays: http://www.digitalmars.com/d/2.0/arrays.html s[] = t; // the 3 elements of t[3] are copied into s[3] s[] = t[]; // the 3 elements of t[3] are copied into s[3] s[] = 3; // same as s[0] = 3, s[1] = 3, s[2] = 3 p[0..2] = 3; // same as p[0] = 3, p[1] = 3 Following Python Zen, I don't like to have two different syntaxes to do the same thing, so this can become a syntax error: int[3] a, b; a[] = a; So you must write: int[3] a, b; a[] = a[]; This is also allowed: int[3] a; int i; a[] = i; This has to be a syntax error: int[3] a; int i; a[] = i[]; So once array.init is [init, init, ...] this will be allowed (but can't the compiler recognize and optimize this situation in many cases?): int[3] a; a[] = a.init[]; To save memory the programmer can use: int[3] a; a[] = a[0].init; ------------------------ Regarding the assert(float.init is NaN) and the "is" meant as binary compare I don't mind it. Making the language more orthogonal and removing special cases reduces language complexity in programmes heads, books, and makes generic code simpler. Bye and thank you, bearophile
Mar 13 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Following Python Zen, I don't like to have two different syntaxes to do the
same thing, [...]<
That was not clear enough, second try: a[] = b[]; static dynamic static OK1 OK1 dynamic OK1 OK1 a = b[]; static dynamic static Err Err dynamic Err Err a[] = b; static dynamic static Err Err dynamic Err Err a = b; static dynamic static Err2 Err dynamic Err OK2 int i; a=i; static dynamic Err Err int i; a[] = i; static dynamic OK3 OK3 Key: Err = Syntax error OK1 = Copies all items from an array to the oter. OK2 = Copies just the stuct of the dynamic array, array body not copied. OK3 = Copies the value to all the items of the array. Err2 = Syntax error, becase there is no reference to copy, better keep language tidy. You can see I have disallowed this too: int a, b; a = b; This breaks generic code, but Andrei said that it's bad when the same syntax can be O(1) (because the same done on dynamic arrays is a O(1)) or O(n). And the semantics is too much different. You are free to disagree. The good thing is that now I have those matrices of all cases, so it's easy to see and design :-) The final version of those matrices can be added to this page: http://www.digitalmars.com/d/2.0/arrays.html Bye, bearophile
Mar 13 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 13 Mar 2010 15:13:26 -0500, Walter Bright  
<newshound1 digitalmars.com> wrote:

 Currently, given an array:

     alias T[3] A;
     A a;

 the default initializer for A, A.init, is T.init. It is done this way  
 for memory efficiency, as:

     a = A.init;

 doesn't need to create an array for the rvalue. But it does cause  
 generic programming problems, especially with the advent of static  
 arrays now being passed by value rather than by ref.

 So, I propose changing A.init from being T.init to being [T.init,  
 T.init, T.init].

 What do you think?
Is that going to allocate heap data as the current array literal does? If so, it's a step backwards. It needs to be ROM data. -Steve
Mar 15 2010
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Steven Schveighoffer:
 Is that going to allocate heap data as the current array literal does?  If  
 so, it's a step backwards.  It needs to be ROM data.
I think my two posts solve your problems and doubts: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=107605 http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=107607 Bye, bearophile
Mar 15 2010
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
grauzone:
 This assert should never fail:
 
 T x;
 assert(x is T.init);
 
 (Right now it fails for floats because of NaN - can we fix this too? 
 "is" should always do byte comparisons.)
I have added it as enhancement request because I think it's a good idea: http://d.puremagic.com/issues/show_bug.cgi?id=3981 Bye, bearophile
Mar 17 2010