www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - initializedArray

reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I think it would be cool to have an initializedArray function, which
creates and initializes an array with a *specific* initializer. A
hardcoded example would be:

import std.array;

auto initializedArray(F:float[])(size_t size, float init)
{
    auto arr = uninitializedArray!(float[])(size);
    arr[] = init;
    return arr;
}

void main()
{
    float[] arr = initializedArray!(float[])(3, 0.0f);
    assert(arr[] == [0.0f, 0.0f, 0.0f]);
}

Currently there's no D syntax for using new on arrays and specifying a
specific initializer, so maybe we should have this as a library
function. Thoughts?
Dec 20 2011
next sibling parent "Paul D. Anderson" <paul.d.removethis.anderson comcast.andthis.net> writes:
I think this is a great idea and a good example of adding to the 
library rather than changing the syntax.

Paul

"Wouldn't the sentence 'I want to put a hyphen between the words 
Fish and And and And and Chips in my Fish-And-Chips sign' have 
been clearer if quotation marks had been placed before Fish, and 
between Fish and and, and and and And, and And and and, and and 
and And, and And and and, and and and Chips, as well as after 
Chips?" — Martin Gardner

On Tuesday, 20 December 2011 at 12:55:18 UTC, Andrej Mitrovic 
wrote:
 I think it would be cool to have an initializedArray function, 
 which
 creates and initializes an array with a *specific* initializer. 
 A
 hardcoded example would be:

 import std.array;

 auto initializedArray(F:float[])(size_t size, float init)
 {
   auto arr = uninitializedArray!(float[])(size);
   arr[] = init;
   return arr;
 }

 void main()
 {
   float[] arr = initializedArray!(float[])(3, 0.0f);
   assert(arr[] == [0.0f, 0.0f, 0.0f]);
 }

 Currently there's no D syntax for using new on arrays and 
 specifying a
 specific initializer, so maybe we should have this as a library
 function. Thoughts?
Dec 20 2011
prev sibling parent reply "Dejan Lekic" <dejan.lekic gmail.com> writes:
I would go even further, and give a *function* as an argument - 
function that will be used to initialise values.
Dec 20 2011
next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 12/20/11, Dejan Lekic <dejan.lekic gmail.com> wrote:
 I would go even further, and give a *function* as an argument -
 function that will be used to initialise values.
Well I don't know about functions yet, but I did need to use another array as an initializer. So the new implementation takes care of that via lockstep: http://www.ideone.com/gKFTK
Dec 20 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
*Also those two templates can be merged, I just have to change the constraints.
Dec 20 2011
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Tue, Dec 20, 2011 at 21:20, Andrej Mitrovic
<andrej.mitrovich gmail.com> wrote:
 On 12/20/11, Dejan Lekic <dejan.lekic gmail.com> wrote:
 I would go even further, and give a *function* as an argument -
 function that will be used to initialise values.
Well I don't know about functions yet, but I did need to use another array as an initializer. So the new implementation takes care of that via lockstep:
from : http://www.ideone.com/gKFTK : unittest { auto arr2 = initializedArray!(int[][])([[1, 2], [3, 4]], 2, 2); assert(arr2 == [[1, 2], [3, 4]]); } 1) What's the difference with using auto arr2 == [[1,2],[3,4]].dup; ? (I honestly asks, I don't know much about D's assignements) 2) You can get the lengths of [[1,2],[3,4]], so the 2,2 args is redundant. What happens if you type: auto arr2 = initializedArray!(int[][])([[1, 2], [3, 4]], 4, 10); 3) I still think you should relax the constraint on the init value's type. You do not need it to be *exactly* BaseElementType!T. Thats stops you from writing auto arr2 = initializedArray!(float[][])(3, 2,3); 4-ish) No need to attribute the rank/BaseElementType code to me :-)
Dec 20 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 12/20/11, Philippe Sigaud <philippe.sigaud gmail.com> wrote:
 1) What's the difference with using auto arr2 == [[1,2],[3,4]].dup;  ?
 (I honestly asks, I don't know much about D's assignements)
dup is not a deep copy, it only copies the first elements. The first elements are two slices, so: void main() { auto a = [[1, 2], [3, 4]]; auto b = a.dup; a[0][0] = 10; assert(b[] == [[1, 2], [3, 4]]); // fails, b[0][0] is 10 }
 2) You can get the lengths of [[1,2],[3,4]], so the 2,2 args is
 redundant. What happens if you type:

 auto arr2 = initializedArray!(int[][])([[1, 2], [3, 4]], 4, 10);
Right, it's broken to say the least. That's what I get for a 10 second implementation.. Btw, uninitializedArray takes variadic arguments, how would I get the lengths of the dimensions as a tuple that can be passed in place of the variadic argument? I.e.: auto dupArray(int[][] src) // say src is int[1][2] { auto arr = uninitializedArray!(int[][])( /* need 1, 2 here */ ); // ..then copy each element.. } I could use a mixin, but there should be an easier way to do this? You're good with templates so I'm asking you! :)
 3) I still think you should relax the constraint on the init value's
 type. You do not need it to be *exactly* BaseElementType!T. Thats
 stops you from writing

 auto arr2 = initializedArray!(float[][])(3,  2,3);
I often fall to this trap. I think there's a syntax for checking if a type is implicitly convertible to another type? I haven't read your book fully yet, btw.
 4-ish) No need to attribute the rank/BaseElementType code to me :-)
I say the same thing for when people use my code, but usually it's best not to assume ownership. :)
Dec 20 2011
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Tue, Dec 20, 2011 at 23:42, Andrej Mitrovic
<andrej.mitrovich gmail.com> wrote:
 On 12/20/11, Philippe Sigaud <philippe.sigaud gmail.com> wrote:
 1) What's the difference with using auto arr2 =3D=3D [[1,2],[3,4]].dup; =
=C2=A0?
 (I honestly asks, I don't know much about D's assignements)
dup is not a deep copy, it only copies the first elements. The first elements are two slices
Ah OK. Where as your version does a deep dupping, I see.
 2) You can get the lengths of [[1,2],[3,4]], so the 2,2 args is
 redundant. What happens if you type:

 auto arr2 =3D initializedArray!(int[][])([[1, 2], [3, 4]], 4, 10);
Right, it's broken to say the least. That's what I get for a 10 second implementation..
I tend to do that also :)
 Btw, uninitializedArray takes variadic arguments, how
 would I get the lengths of the dimensions as a tuple that can be
 passed in place of the variadic argument? I.e.:

 auto dupArray(int[][] src) =C2=A0// say src is int[1][2]
 {
 =C2=A0 =C2=A0auto arr =3D uninitializedArray!(int[][])( /* need 1, 2 here=
*/ );
 =C2=A0 =C2=A0// ..then copy each element..
 }
Having thought a bit more about this, there is a difference between static and dynamic arrays. For static arrays, the length is part of the type, so getting them should be straightforward. Untested: size_t[] arrayLengths(A)(A a) if (isStaticArray!A) { static if (isStaticArray!(ElementType!A)) return arrayLengths(a[0]) ~ a.length; else return [a.length]; } But for dynamic arrays, int[][] can be a jagged (non square) array. And now that array literal are dynamic, the only way I see would be to collect the max length for all dimensions. [[1,2,3], [4,5]] -> 2 rows, 3 columns.
 3) I still think you should relax the constraint on the init value's
 type. You do not need it to be *exactly* BaseElementType!T. Thats
 stops you from writing

 auto arr2 =3D initializedArray!(float[][])(3, =C2=A02,3);
I often fall to this trap. I think there's a syntax for checking if a type is implicitly convertible to another type?
There is 'is(A : B)', but when I tried this with your code, it didn't work (maybe I was confused between double and floats). That's why I used std.traits.isImplicitlyConvertible!(From,To)
Dec 20 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 12/21/11, Philippe Sigaud <philippe.sigaud gmail.com> wrote:
 size_t[] arrayLengths(A)(A a) if (isStaticArray!A)
 {
     static if (isStaticArray!(ElementType!A))
 	return arrayLengths(a[0]) ~  a.length;
     else
         return [a.length];
 }
That returns an array, but I can't pass an array in place of a variadic argument. The prototype of uninitializedArray is: auto uninitializedArray(T, I...)(I sizes) if(allSatisfy!(isIntegral, I)) { }
Dec 21 2011
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Ok just realized I can't use a mixin, lengths are dynamic, heheh. That
went over my head. I'll see what else I can do..

On 12/21/11, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 On 12/21/11, Philippe Sigaud <philippe.sigaud gmail.com> wrote:
 size_t[] arrayLengths(A)(A a) if (isStaticArray!A)
 {
     static if (isStaticArray!(ElementType!A))
 	return arrayLengths(a[0]) ~  a.length;
     else
         return [a.length];
 }
That returns an array, but I can't pass an array in place of a variadic argument. The prototype of uninitializedArray is: auto uninitializedArray(T, I...)(I sizes) if(allSatisfy!(isIntegral, I)) { }
Dec 21 2011