Thread overview
Creating an array of default-constructed class instances
Feb 10, 2013
Simon
Feb 10, 2013
Maxim Fomin
Feb 10, 2013
Ali Çehreli
Feb 10, 2013
Ali Çehreli
Feb 10, 2013
Simon
Feb 10, 2013
Philippe Sigaud
Feb 10, 2013
Jos van Uden
Feb 10, 2013
monarch_dodra
Feb 10, 2013
Ali Çehreli
Feb 10, 2013
monarch_dodra
February 10, 2013
Hi, I'm new to the D programming language.  Overall I'm liking
things very much, but I'm still getting the hang of a few things.

Here's a basic programming pattern: I have a class called Thing,
and while I'm coding I decide I need N Thing instances.

In C++ that's a matter of

std::vector<Thing> things(N);

In python, I can use a list comprehension.

things = [Thing() for _ in range(N)]

However, the obvious D version doesn't work.

auto things = new Thing[N];

Because Thing.init is null, this produces an array of null
references.  Of course, I can write a for loop to fill in the
array after creation, but this feels very un-D-like.  Is there a
straightforward way to create a bunch of class instances?
February 10, 2013
On Sunday, 10 February 2013 at 06:14:37 UTC, Simon wrote:
> Hi, I'm new to the D programming language.  Overall I'm liking
> things very much, but I'm still getting the hang of a few things.
>
> Here's a basic programming pattern: I have a class called Thing,
> and while I'm coding I decide I need N Thing instances.
>
> In C++ that's a matter of
>
> std::vector<Thing> things(N);
>
> In python, I can use a list comprehension.
>
> things = [Thing() for _ in range(N)]
>
> However, the obvious D version doesn't work.
>
> auto things = new Thing[N];
>
> Because Thing.init is null, this produces an array of null
> references.  Of course, I can write a for loop to fill in the
> array after creation, but this feels very un-D-like.  Is there a
> straightforward way to create a bunch of class instances?

You can create separate function which fills array with instances and return it. You can make Thing a struct aliased to array of classes which again initializes properly in constructor an array. But then you should take care that struct constructor is called.
February 10, 2013
On 02/09/2013 10:14 PM, Simon wrote:
> Hi, I'm new to the D programming language. Overall I'm liking
> things very much, but I'm still getting the hang of a few things.
>
> Here's a basic programming pattern: I have a class called Thing,
> and while I'm coding I decide I need N Thing instances.
>
> In C++ that's a matter of
>
> std::vector<Thing> things(N);
>
> In python, I can use a list comprehension.
>
> things = [Thing() for _ in range(N)]
>
> However, the obvious D version doesn't work.
>
> auto things = new Thing[N];
>
> Because Thing.init is null, this produces an array of null
> references. Of course, I can write a for loop to fill in the
> array after creation, but this feels very un-D-like. Is there a
> straightforward way to create a bunch of class instances?

Here is one way:

import std.stdio;
import std.range;
import std.algorithm;

class Thing
{
    int i;

    this(int i)
    {
        this.i = i;
    }
}

void main()
{
    auto things = iota(10).map!(i => new Thing(i))().array;
}

Ali

-- 
D Programming Language Tutorial: http://ddili.org/ders/d.en/index.html

February 10, 2013
On 02/09/2013 10:52 PM, Ali Çehreli wrote:

>   auto things = iota(10).map!(i => new Thing(i))().array;

Actually, without the extra parentheses:

    auto things = iota(10).map!(i => new Thing(i)).array;

Ali

February 10, 2013
On Sunday, 10 February 2013 at 06:57:42 UTC, Ali Çehreli wrote:
> On 02/09/2013 10:52 PM, Ali Çehreli wrote:
>
> >   auto things = iota(10).map!(i => new Thing(i))().array;
>
> Actually, without the extra parentheses:
>
>     auto things = iota(10).map!(i => new Thing(i)).array;
>
> Ali

It's a shame there isn't any simple syntax for it, but that's some neat and flexible code.

Thanks!
February 10, 2013
On Sun, Feb 10, 2013 at 8:40 AM, Simon <none@example.org> wrote:

>>     auto things = iota(10).map!(i => new Thing(i)).array;
>>
>> Ali
>
>
> It's a shame there isn't any simple syntax for it, but that's some neat and flexible code.

Oh, you can easily use a template:

import std.array;
import std.algorithm;
import std.conv;
import std.range;
import std.stdio;

class Thing
{
    int i;
    this(int i)
    {
        this.i = i;
    }
    void toString(scope void delegate(const(char)[]) sink) const
    {
        sink("Thing: " ~ to!string(i));
    }
}

/// Helper template
What[] makeArray(alias What)(size_t size)
{
    return iota(size).map!(i => new What(i)).array;
}

void main()
{
    auto things = makeArray!(Thing)(10);
    writeln(things);
}
February 10, 2013
On 10-2-2013 7:14, Simon wrote:
> Hi, I'm new to the D programming language.  Overall I'm liking
> things very much, but I'm still getting the hang of a few things.
>
> Here's a basic programming pattern: I have a class called Thing,
> and while I'm coding I decide I need N Thing instances.
>
> In C++ that's a matter of
>
> std::vector<Thing> things(N);
>
> In python, I can use a list comprehension.
>
> things = [Thing() for _ in range(N)]
>
> However, the obvious D version doesn't work.
>
> auto things = new Thing[N];
>
> Because Thing.init is null, this produces an array of null
> references.  Of course, I can write a for loop to fill in the
> array after creation, but this feels very un-D-like.  Is there a
> straightforward way to create a bunch of class instances?

import std.stdio, std.algorithm;

class Thing {
    int i;
    this(int i) {
        this.i = i;
    }
}

void main()
{
   auto things = new Thing[10];
   fill(things, new Thing(5));

   foreach (t; things)
        writef("%d ", t.i);
}
February 10, 2013
On Sunday, 10 February 2013 at 09:48:04 UTC, Jos van Uden wrote:
> On 10-2-2013 7:14, Simon wrote:
>> Hi, I'm new to the D programming language.  Overall I'm liking
>> things very much, but I'm still getting the hang of a few things.
>>
>> Here's a basic programming pattern: I have a class called Thing,
>> and while I'm coding I decide I need N Thing instances.
>>
>> In C++ that's a matter of
>>
>> std::vector<Thing> things(N);
>>
>> In python, I can use a list comprehension.
>>
>> things = [Thing() for _ in range(N)]
>>
>> However, the obvious D version doesn't work.
>>
>> auto things = new Thing[N];
>>
>> Because Thing.init is null, this produces an array of null
>> references.  Of course, I can write a for loop to fill in the
>> array after creation, but this feels very un-D-like.  Is there a
>> straightforward way to create a bunch of class instances?
>
> import std.stdio, std.algorithm;
>
> class Thing {
>     int i;
>     this(int i) {
>         this.i = i;
>     }
> }
>
> void main()
> {
>    auto things = new Thing[10];
>    fill(things, new Thing(5));
>
>    foreach (t; things)
>         writef("%d ", t.i);
> }

HELL NO!!!!

What you did just right there is allocate a *single* thing _instance_  and then place 10 _references_ to that same thing in the array.
February 10, 2013
On Sunday, 10 February 2013 at 06:14:37 UTC, Simon wrote:
> Hi, I'm new to the D programming language.  Overall I'm liking
> things very much, but I'm still getting the hang of a few things.
>
> Here's a basic programming pattern: I have a class called Thing,
> and while I'm coding I decide I need N Thing instances.
>
> In C++ that's a matter of
>
> std::vector<Thing> things(N);
>
> In python, I can use a list comprehension.
>
> things = [Thing() for _ in range(N)]
>
> However, the obvious D version doesn't work.
>
> auto things = new Thing[N];
>
> Because Thing.init is null, this produces an array of null
> references.  Of course, I can write a for loop to fill in the
> array after creation, but this feels very un-D-like.  Is there a
> straightforward way to create a bunch of class instances?

The difference is that C++ will *place* the instances inside the vector. A *true* C++ equivalent would be to declare:
std::vector<Thing*> things(N);

As you can see, same problem.

Honestly, there are a lot of fancy ways to go around the problem, but quite frankly,I think simple is best:

//----
auto myThings = new Thing[](N);
foreach(ref aThing; myThings)
    aThing = new Thing();
//-----

It's not fancy, but it gets the job done. You won't confuse anyone with the code, and there is very little risk of subtle bugs (appart from forgetting the ref in the foreach loop.
February 10, 2013
On 02/10/2013 03:18 AM, monarch_dodra wrote:
> On Sunday, 10 February 2013 at 09:48:04 UTC, Jos van Uden wrote:

>> auto things = new Thing[10];
>> fill(things, new Thing(5));

> What you did just right there is allocate a *single* thing _instance_
> and then place 10 _references_ to that same thing in the array.

And in case that is what we really wanted, there is the simpler but sometimes confusing array-wise syntax:

    auto things = new Thing[10];
    things[] = new Thing(5);

Ali