3

I am using the D programming language. I want to have a struct containing a multidimensional static array of ints initially filled with a non-zero value (in my case, zero is a valid entry, and I want to initially mark all entries as invalid). As it is a struct, it can not have a default constructor. Instead, I can supply a default value for the member of the struct.

The question is: how do I write this multidimensional array value in a short and readable way? Is there any convenience function, special-case syntax or idiom to do that?


Here is what I came up with.

import std.range;
import std.stdio;

struct S
{
    static immutable int SIZE =  3;
    static immutable int NA   = -1;

    int [SIZE] [SIZE] a = NA.repeat(SIZE).array().repeat(SIZE).array();
}

void main()
{
    S s;
    writeln(s);
}

This prints the array of -1s as expected:

S([[-1, -1, -1], [-1, -1, -1], [-1, -1, -1]])

Still, the expression NA.repeat(SIZE).array().repeat(SIZE).array() looks lengthy, and I suspect there could be a better (more idiomatic, more readable) way to express my intent.


Update with a few more attempts:

  1. int [SIZE] [SIZE] a = NA; does not compile, even with the current beta: dmd-2.066-b2.

  2. int [SIZE] [SIZE] a = NA.repeat (SIZE).array (); compiles and does the thing. Still, the consistency suffers.

  3. int [SIZE] [SIZE] a = [NA, NA, NA]; looks like it is essentially the above expression, simplified. It compiles but fills only the first three-element subarray with NAs. The other two subarrays contain some garbage-like stuff. Is that a partial initialization feature of some kind? To me, it looks more like a bug, like, compiler accepting invalid code.

  4. int [SIZE] [SIZE] a = [NA]; sets the first subarray to [-1, 0, 0] and the rest to the same garbage as the previous attempt.

  5. There is also fill in std.algorithm, but it works for ranges (not ranges of ranges), and does not look like it's readily usable in an initializer. At least it won't be shorter.

Gassa
  • 8,546
  • 3
  • 29
  • 49
  • 2
    huh, for a single dimensional array, you can just set it to an integer. For a multidim static array it seems to me that maybe the same thing should work, since they are really the same memory wise. of course this is a compiler enhancement rather than a real answer. tbh i'd just take your long line and make a function out of it so it is mroe readable at the usage point and call it done. – Adam D. Ruppe Jul 07 '14 at 01:30
  • If I remember well, there were talks about improving the static array initialization to allow something like `int[100][100] arr = 40;`. Try the new 2.066b1, maybe it is there. – DejanLekic Jul 08 '14 at 07:44
  • @Adam: you mean a recursive template specialized for array and non-array elements? That's a nice idea, but still a bit overkill for such a simple task, don't you think? – Gassa Jul 10 '14 at 13:48
  • @DejanLekic: tried with 2.066b2, not working. See the update in the question. – Gassa Jul 10 '14 at 13:49

1 Answers1

2

What about something like this:

module main;
import std.stdio: writeln;

enum SIZE =  3;
enum NA = -1;

struct Int {
    int v = -1;
    alias v this;
}

struct S
{
    Int [SIZE] [SIZE] a;
}

void main()
{
    S s;
    writeln(s);
}
Kozzi11
  • 2,413
  • 12
  • 17
  • That looks nice, thank you! And with a simple benchmark, `dmd -O -release -inline -noboundscheck` produces the exact same assembly. So, optimization opportunities for that `Int` struct are comparable to a simple `int`, which can also be important. – Gassa Jul 15 '14 at 09:46
  • ("The exact same assembly" refers to further usage, not initialization, of the struct.) – Gassa Jul 15 '14 at 09:54