www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Dynamic array creation with default

reply bearophile <bearophileHUGS lycos.com> writes:
To create a nD dynamic array and initialize it to a constant value (different
from the init) you currently do something like this:


auto mat = new bool[][](10, 20);
foreach (ref row; mat)
    row[] = true;


Currently this D code initializes the matrix items to bool.init (false), and
then initializes it all again with true. You sometimes forget to use the "ref",
and they are three lines of code for a single operation.

Time ago I have seen this as a way to simplify the code, similar to the syntax
for fixed-sized arrays (but Andrei says this is not good):


auto mat = new bool[][](10, 20) = true;



to do the same thing):

let mat = Array2D.create 10 20 true


This has suggested me to add one optional initialization value in D too:

auto mat = new bool[][](10, 20, true);


It's a bit more bug-prone, because you sometimes forget a [] and you write:

auto mat = new int[](10, 20);

Instead of:

auto mat = new int[][](10, 20);

And instead of a matrix you get a 1D array initialized to some integer value.
But I think it's not a big problem.

A bigger problem is that currently this code is accepted, so you can't use an
optional initialization value:

auto a = new int[][](5);

A solution is to always require as many sizes as dimensions, so you have to
write:

auto a = new int[][](5, 0); // OK, no default
auto a = new int[][](5, 0, 30); // 30 is the default

Another solution is to introduce named arguments and always require the
argument name for the default value, when you add a default value:

auto mat = new bool[][](10, 20, default=true);

Using both solutions at the same time is possible.

In theory this syntax is also useful to initialize the array to something not
constant, using a delegate (in this universe when uniform has a single input,
it acts like iota(n)), this is a typical use case:

auto mat10 = new int[][](10, 20, default={ return uniform(9); });

This replaces a function table() that I have suggested for Phobos.

Bye,
bearophile
Aug 22 2011
parent reply foobar <foo bar.com> writes:
== Quote from bearophile (bearophileHUGS lycos.com)'s article
 To create a nD dynamic array and initialize it to a constant value (different
from the init) you currently do something like this:
 auto mat = new bool[][](10, 20);
 foreach (ref row; mat)
     row[] = true;
 Currently this D code initializes the matrix items to bool.init (false), and
then initializes it all again with true. You sometimes forget to use the "ref", and they are three lines of code for a single operation.
 Time ago I have seen this as a way to simplify the code, similar to the syntax
for fixed-sized arrays (but Andrei says this is not good):
 auto mat = new bool[][](10, 20) = true;

to
do the same thing):
 let mat = Array2D.create 10 20 true
 This has suggested me to add one optional initialization value in D too:
 auto mat = new bool[][](10, 20, true);
 It's a bit more bug-prone, because you sometimes forget a [] and you write:
 auto mat = new int[](10, 20);
 Instead of:
 auto mat = new int[][](10, 20);
 And instead of a matrix you get a 1D array initialized to some integer value.
But I think it's not a big problem.
 A bigger problem is that currently this code is accepted, so you can't use an
optional initialization value:
 auto a = new int[][](5);
 A solution is to always require as many sizes as dimensions, so you have to
write:
 auto a = new int[][](5, 0); // OK, no default
 auto a = new int[][](5, 0, 30); // 30 is the default
 Another solution is to introduce named arguments and always require the
argument
name for the default value, when you add a default value:
 auto mat = new bool[][](10, 20, default=true);
 Using both solutions at the same time is possible.
 In theory this syntax is also useful to initialize the array to something not
constant, using a delegate (in this universe when uniform has a single input, it acts like iota(n)), this is a typical use case:
 auto mat10 = new int[][](10, 20, default={ return uniform(9); });
 This replaces a function table() that I have suggested for Phobos.
 Bye,
 bearophile
you raise a valid concern but this looks too complicated. I'd suggest to simplify into only two cases. // 1) T.INIT - as you suggested the dimension should be checked auto foo = new int[][](10, 20); // correct auto foo1 = new int[][](10); // compilation error // 2) function of the array dimension auto bar = new int[][](10, 20, (int x, int y) { return x*y; } ); // if you want a default value just use: auto bar1 = new int[][](10, 20, { return 3; } ); For fixed-sized arrays the function would be CTFE-able.
Aug 23 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
foobar:

 you raise a valid concern but this looks too complicated.
 I'd suggest to simplify into only two cases.
 
 // 1) T.INIT - as you suggested the dimension should be checked
 auto foo = new int[][](10, 20); // correct
 auto foo1 = new int[][](10); // compilation error
Keep in mind that currently this is correct and it generates a 1D dynamic array: auto v = new int[10];
 // 2) function of the array dimension
 auto bar = new int[][](10, 20, (int x, int y) { return x*y; } );
 
 // if you want a default value just use:
 auto bar1 = new int[][](10, 20, { return 3; } );
 
 For fixed-sized arrays the function would be CTFE-able.
This is more complex than my suggestions :-) The most common case is the initialization with a constant value. I'd like this case to be as efficient as possible, so I don't like the { return 3; }. The case with a more complex delegate is interesting to initialize constant arrays: immutable m = new int[][](10, 20, (int x, int y){ return x*y; }); But in my opinion this is not a so common operation. And it's not able to replace Python-style array comps: foo = [x ** x for x in lazyIterable] So I don't like your proposals. Maybe dsimcha will give a Phobos function to allocate & initialize a nD array with a given const value. Bye, bearophile
Aug 23 2011
parent reply foobar <foo bar.com> writes:
== Quote from bearophile (bearophileHUGS lycos.com)'s article
 foobar:
 you raise a valid concern but this looks too complicated.
 I'd suggest to simplify into only two cases.

 // 1) T.INIT - as you suggested the dimension should be checked
 auto foo = new int[][](10, 20); // correct
 auto foo1 = new int[][](10); // compilation error
Keep in mind that currently this is correct and it generates a 1D dynamic array: auto v = new int[10];
Isn't this an inconsistency in the language? // Generally speaking, allocates an instance of T on the heap auto foo = new T; However, "int[10]" and "new int[10]" are different types.
 // 2) function of the array dimension
 auto bar = new int[][](10, 20, (int x, int y) { return x*y; } );

 // if you want a default value just use:
 auto bar1 = new int[][](10, 20, { return 3; } );

 For fixed-sized arrays the function would be CTFE-able.
This is more complex than my suggestions :-) The most common case is the initialization with a constant value. I'd like this
case to be as efficient as possible, so I don't like the { return 3; }. This syntax could be simplified if we drop "return" as suggested in another thread. Also, couldn't we employ "lazy" for this? I don't remember how it works, does it accept a value on the call-site? On the other hand, I dislike the named-parameter suggestion. Named parameters indicate in my eyes a design bug.
 The case with a more complex delegate is interesting to initialize constant
arrays:
 immutable m = new int[][](10, 20, (int x, int y){ return x*y; });
 But in my opinion this is not a so common operation. And it's not able to
replace Python-style array comps:
 foo = [x ** x for x in lazyIterable]
 So I don't like your proposals.
 Maybe dsimcha will give a Phobos function to allocate & initialize a nD array
with a given const value.
 Bye,
 bearophile
Aug 23 2011
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/23/2011 03:15 PM, foobar wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 foobar:
 you raise a valid concern but this looks too complicated.
 I'd suggest to simplify into only two cases.

 // 1) T.INIT - as you suggested the dimension should be checked
 auto foo = new int[][](10, 20); // correct
 auto foo1 = new int[][](10); // compilation error
Keep in mind that currently this is correct and it generates a 1D dynamic array: auto v = new int[10];
Isn't this an inconsistency in the language? // Generally speaking, allocates an instance of T on the heap auto foo = new T; However, "int[10]" and "new int[10]" are different types.
int and typeof(new int) are different types too.
 // 2) function of the array dimension
 auto bar = new int[][](10, 20, (int x, int y) { return x*y; } );

 // if you want a default value just use:
 auto bar1 = new int[][](10, 20, { return 3; } );

 For fixed-sized arrays the function would be CTFE-able.
This is more complex than my suggestions :-) The most common case is the initialization with a constant value. I'd like this
case to be as efficient as possible, so I don't like the { return 3; }. This syntax could be simplified if we drop "return" as suggested in another thread. Also, couldn't we employ "lazy" for this? I don't remember how it works, does it accept a value on the call-site? On the other hand, I dislike the named-parameter suggestion. Named parameters indicate in my eyes a design bug.
 The case with a more complex delegate is interesting to initialize constant
arrays:
 immutable m = new int[][](10, 20, (int x, int y){ return x*y; });
 But in my opinion this is not a so common operation. And it's not able to
replace Python-style array comps:
 foo = [x ** x for x in lazyIterable]
 So I don't like your proposals.
 Maybe dsimcha will give a Phobos function to allocate&  initialize a nD array
with a given const value.
 Bye,
 bearophile
Aug 23 2011
parent foobar <foo bar.com> writes:
== Quote from Timon Gehr (timon.gehr gmx.ch)'s article
 On 08/23/2011 03:15 PM, foobar wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 foobar:
 you raise a valid concern but this looks too complicated.
 I'd suggest to simplify into only two cases.

 // 1) T.INIT - as you suggested the dimension should be checked
 auto foo = new int[][](10, 20); // correct
 auto foo1 = new int[][](10); // compilation error
Keep in mind that currently this is correct and it generates a 1D dynamic array: auto v = new int[10];
Isn't this an inconsistency in the language? // Generally speaking, allocates an instance of T on the heap auto foo = new T; However, "int[10]" and "new int[10]" are different types.
int and typeof(new int) are different types too.
"int" and "new int" are both an integer, the only difference is the memory location. "int[10]" is a fixed-size array vs. "new int[10]" which is a dynamic array with a completely different interface.
Aug 23 2011
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/23/11 6:15 AM, foobar wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 foobar:
 you raise a valid concern but this looks too complicated.
 I'd suggest to simplify into only two cases.

 // 1) T.INIT - as you suggested the dimension should be checked
 auto foo = new int[][](10, 20); // correct
 auto foo1 = new int[][](10); // compilation error
Keep in mind that currently this is correct and it generates a 1D dynamic array: auto v = new int[10];
Isn't this an inconsistency in the language? // Generally speaking, allocates an instance of T on the heap auto foo = new T; However, "int[10]" and "new int[10]" are different types.
I hate that, too. Walter hates it, too, but we both reckon it's too late now to change things. It makes it impossible to create an instance of the type "int[10]" dynamically because of an gratuitous syntactic special case. It comes from C++, where it was an unforced error. Andrei
Aug 23 2011
next sibling parent reply foobar <foo bar.com> writes:
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 On 8/23/11 6:15 AM, foobar wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 foobar:
 you raise a valid concern but this looks too complicated.
 I'd suggest to simplify into only two cases.

 // 1) T.INIT - as you suggested the dimension should be checked
 auto foo = new int[][](10, 20); // correct
 auto foo1 = new int[][](10); // compilation error
Keep in mind that currently this is correct and it generates a 1D dynamic array: auto v = new int[10];
Isn't this an inconsistency in the language? // Generally speaking, allocates an instance of T on the heap auto foo = new T; However, "int[10]" and "new int[10]" are different types.
I hate that, too. Walter hates it, too, but we both reckon it's too late now to change things. It makes it impossible to create an instance of the type "int[10]" dynamically because of an gratuitous syntactic special case. It comes from C++, where it was an unforced error. Andrei
Is it possible to deprecate/disallow "new T[size]" since we have an alternate syntax for it? At least until D3 comes along when we could change this. This also aligns with your goal of moving built-in types from the compiler/runtime to the library (AAs..) which I think is an important goal. I'd like to see dynamic arrays as well as AAs as plain templates in phobos and D itself only provides a thin layer of syntax sugar for literals and such.
Aug 23 2011
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08/23/2011 05:11 PM, foobar wrote:
 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 On 8/23/11 6:15 AM, foobar wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 foobar:
 you raise a valid concern but this looks too complicated.
 I'd suggest to simplify into only two cases.

 // 1) T.INIT - as you suggested the dimension should be checked
 auto foo = new int[][](10, 20); // correct
 auto foo1 = new int[][](10); // compilation error
Keep in mind that currently this is correct and it generates a 1D dynamic array: auto v = new int[10];
Isn't this an inconsistency in the language? // Generally speaking, allocates an instance of T on the heap auto foo = new T; However, "int[10]" and "new int[10]" are different types.
I hate that, too. Walter hates it, too, but we both reckon it's too late now to change things. It makes it impossible to create an instance of the type "int[10]" dynamically because of an gratuitous syntactic special case. It comes from C++, where it was an unforced error. Andrei
Is it possible to deprecate/disallow "new T[size]" since we have an alternate syntax for it? At least until D3 comes along when we could change this. This also aligns with your goal of moving built-in types from the compiler/runtime to the library (AAs..) which I think is an important goal. I'd like to see dynamic arrays as well as AAs as plain templates in phobos and D itself only provides a thin layer of syntax sugar for literals and such.
Dynamic arrays should stay fully built-in imo. What would be the benefit of having them in the library? To generate decent machine code and optimize away some boundary checks from safe code, compilers would still have to treat them specially.
Aug 23 2011
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/23/11 8:11 AM, foobar wrote:
 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 On 8/23/11 6:15 AM, foobar wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 foobar:
 you raise a valid concern but this looks too complicated.
 I'd suggest to simplify into only two cases.

 // 1) T.INIT - as you suggested the dimension should be checked
 auto foo = new int[][](10, 20); // correct
 auto foo1 = new int[][](10); // compilation error
Keep in mind that currently this is correct and it generates a 1D dynamic array: auto v = new int[10];
Isn't this an inconsistency in the language? // Generally speaking, allocates an instance of T on the heap auto foo = new T; However, "int[10]" and "new int[10]" are different types.
I hate that, too. Walter hates it, too, but we both reckon it's too late now to change things. It makes it impossible to create an instance of the type "int[10]" dynamically because of an gratuitous syntactic special case. It comes from C++, where it was an unforced error. Andrei
Is it possible to deprecate/disallow "new T[size]" since we have an alternate syntax for it? At least until D3 comes along when we could change this. This also aligns with your goal of moving built-in types from the compiler/runtime to the library (AAs..) which I think is an important goal. I'd like to see dynamic arrays as well as AAs as plain templates in phobos and D itself only provides a thin layer of syntax sugar for literals and such.
I'm afraid too much paste is out of the tube at this point. Andrei
Aug 23 2011
prev sibling parent reply Don <nospam nospam.com> writes:
foobar wrote:
 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 On 8/23/11 6:15 AM, foobar wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 foobar:
 you raise a valid concern but this looks too complicated.
 I'd suggest to simplify into only two cases.

 // 1) T.INIT - as you suggested the dimension should be checked
 auto foo = new int[][](10, 20); // correct
 auto foo1 = new int[][](10); // compilation error
Keep in mind that currently this is correct and it generates a 1D dynamic array: auto v = new int[10];
Isn't this an inconsistency in the language? // Generally speaking, allocates an instance of T on the heap auto foo = new T; However, "int[10]" and "new int[10]" are different types.
I hate that, too. Walter hates it, too, but we both reckon it's too late now to change things. It makes it impossible to create an instance of the type "int[10]" dynamically because of an gratuitous syntactic special case. It comes from C++, where it was an unforced error. Andrei
Is it possible to deprecate/disallow "new T[size]" since we have an alternate syntax for it? At least until D3 comes along when we could change this. This also aligns with your goal of moving built-in types from the compiler/runtime to the library (AAs..) which I think is an important goal. I'd like to see dynamic arrays as well as AAs as plain templates in phobos and D itself only provides a thin layer of syntax sugar for literals and such.
Please note that moving AAs from built-in to library was little short of a disaster, as far as the compiler is concerned. It created a horrific number of regression bugs (more than 20% of all serious regressions have been caused by it), it's occupied months of time, the job is still only half done, and as far as I can see, there's actually been ZERO benefit from it.
Aug 23 2011
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
Don wrote:
 Please note that moving AAs from built-in to library was little
 short of a disaster, as far as the compiler is concerned.
Amen. The library AAs *still* give me trouble from time to time - been the most buggy thing I've used in D.
Aug 23 2011
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/23/11 12:32 PM, Don wrote:
 foobar wrote:
 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s
 article
 On 8/23/11 6:15 AM, foobar wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 foobar:
 you raise a valid concern but this looks too complicated.
 I'd suggest to simplify into only two cases.

 // 1) T.INIT - as you suggested the dimension should be checked
 auto foo = new int[][](10, 20); // correct
 auto foo1 = new int[][](10); // compilation error
Keep in mind that currently this is correct and it generates a 1D dynamic array: auto v = new int[10];
Isn't this an inconsistency in the language? // Generally speaking, allocates an instance of T on the heap auto foo = new T; However, "int[10]" and "new int[10]" are different types.
I hate that, too. Walter hates it, too, but we both reckon it's too late now to change things. It makes it impossible to create an instance of the type "int[10]" dynamically because of an gratuitous syntactic special case. It comes from C++, where it was an unforced error. Andrei
Is it possible to deprecate/disallow "new T[size]" since we have an alternate syntax for it? At least until D3 comes along when we could change this. This also aligns with your goal of moving built-in types from the compiler/runtime to the library (AAs..) which I think is an important goal. I'd like to see dynamic arrays as well as AAs as plain templates in phobos and D itself only provides a thin layer of syntax sugar for literals and such.
Please note that moving AAs from built-in to library was little short of a disaster, as far as the compiler is concerned. It created a horrific number of regression bugs (more than 20% of all serious regressions have been caused by it), it's occupied months of time, the job is still only half done, and as far as I can see, there's actually been ZERO benefit from it.
We're not seeing benefits because they haven't materialized yet; the benefit so far is that it paves the way toward finalizing the transition. But point taken about the difficulties. Andrei
Aug 23 2011
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 I hate that, too. Walter hates it, too, but we both reckon it's too late 
 now to change things.
With a soft deprecation path I think you will be able to deprecate and remove it in a year. Bye, bearophile
Aug 23 2011
prev sibling next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Tue, 23 Aug 2011 07:45:33 -0700, Andrei Alexandrescu wrote:

 On 8/23/11 6:15 AM, foobar wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 foobar:
 you raise a valid concern but this looks too complicated. I'd suggest
 to simplify into only two cases.

 // 1) T.INIT - as you suggested the dimension should be checked auto
 foo = new int[][](10, 20); // correct auto foo1 = new int[][](10); //
 compilation error
Keep in mind that currently this is correct and it generates a 1D dynamic array: auto v = new int[10];
Isn't this an inconsistency in the language? // Generally speaking, allocates an instance of T on the heap auto foo = new T; However, "int[10]" and "new int[10]" are different types.
I hate that, too. Walter hates it, too, but we both reckon it's too late now to change things.
I, for one, would welcome this change. It's a horrible inconsistency in the language. -Lars
Aug 23 2011
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 23 Aug 2011 10:45:33 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 8/23/11 6:15 AM, foobar wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 foobar:
 you raise a valid concern but this looks too complicated.
 I'd suggest to simplify into only two cases.

 // 1) T.INIT - as you suggested the dimension should be checked
 auto foo = new int[][](10, 20); // correct
 auto foo1 = new int[][](10); // compilation error
Keep in mind that currently this is correct and it generates a 1D dynamic array: auto v = new int[10];
Isn't this an inconsistency in the language? // Generally speaking, allocates an instance of T on the heap auto foo = new T; However, "int[10]" and "new int[10]" are different types.
I hate that, too. Walter hates it, too, but we both reckon it's too late now to change things. It makes it impossible to create an instance of the type "int[10]" dynamically because of an gratuitous syntactic special case. It comes from C++, where it was an unforced error.
It's actually possible, but ugly: auto ptr = (new int[10][](1)).ptr; One really interesting thing to note -- the compiler actually turns struct allocations into array-of-one allocations in the runtime. So this is likely what the compiler would do if it supported direct heap allocation of fixed-sized arrays. -Steve
Aug 24 2011
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-08-24 11:17:08 +0000, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 It's actually possible, but ugly:
 
 auto ptr = (new int[10][](1)).ptr;
 
 One really interesting thing to note -- the compiler actually turns 
 struct  allocations into array-of-one allocations in the runtime.  So 
 this is  likely what the compiler would do if it supported direct heap 
 allocation  of fixed-sized arrays.
A problem with this approach is that it won't work in safe mode because accessing the .ptr property of an array is unsafe in general. But it is perfectly safe to allocate a static array on the GC heap, so it should be allowed… -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 24 2011
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 24 Aug 2011 15:15:54 -0400, Michel Fortin  =

<michel.fortin michelf.com> wrote:

 On 2011-08-24 11:17:08 +0000, "Steven Schveighoffer"  =
 <schveiguy yahoo.com> said:

 It's actually possible, but ugly:
  auto ptr =3D (new int[10][](1)).ptr;
  One really interesting thing to note -- the compiler actually turns =
=
 struct  allocations into array-of-one allocations in the runtime.  So=
=
 this is  likely what the compiler would do if it supported direct hea=
p =
 allocation  of fixed-sized arrays.
A problem with this approach is that it won't work in safe mode becaus=
e =
 accessing the .ptr property of an array is unsafe in general. But it i=
s =
 perfectly safe to allocate a static array on the GC heap, so it should=
=
 be allowed=E2=80=A6
And what would be the type returned by such a function? ;) -Steve
Aug 24 2011
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08/24/2011 11:19 PM, Steven Schveighoffer wrote:
 On Wed, 24 Aug 2011 15:15:54 -0400, Michel Fortin
 <michel.fortin michelf.com> wrote:

 On 2011-08-24 11:17:08 +0000, "Steven Schveighoffer"
 <schveiguy yahoo.com> said:

 It's actually possible, but ugly:
 auto ptr = (new int[10][](1)).ptr;
 One really interesting thing to note -- the compiler actually turns
 struct allocations into array-of-one allocations in the runtime. So
 this is likely what the compiler would do if it supported direct heap
 allocation of fixed-sized arrays.
A problem with this approach is that it won't work in safe mode because accessing the .ptr property of an array is unsafe in general. But it is perfectly safe to allocate a static array on the GC heap, so it should be allowed…
And what would be the type returned by such a function? ;) -Steve
int[N]*
Aug 24 2011