Search code examples
multidimensional-arrayinitializationddmdmember-initialization

D - Set default value for a struct member which is a multidimensional static array


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.


Solution

  • 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);
    }