Thread overview
built-in types inside of a union
Jul 13, 2016
zodd
Jul 13, 2016
Adam D. Ruppe
Jul 13, 2016
Ali Çehreli
Jul 13, 2016
zodd
July 13, 2016
Can I place a dynamic array, an associative array and a string to a union and work with all elements? They are built-in types, but actually not primitive ones (this is not allowed in C++ for example). That's why I'm in doubt. I'm trying to implement something close to variant type (with a few restricted underlying types) for education purposes.

union Foo {
    int[] array;
    int[string] map;
    string str;
}

Foo u;

u.array = [];
u.array ~= 20;
u.array ~= 31;
writeln(u.array);

u.map = (int[string]).init;
u.map["test"] = 20;
u.map["value"] = 31;
writeln(u.map);

u.str = "test";
writeln(u.str);

This code works as I expected but I'm unsure that it's correct.
July 13, 2016
On Wednesday, 13 July 2016 at 12:28:57 UTC, zodd wrote:
> This code works as I expected but I'm unsure that it's correct.

Yes, your code is legal.

What isn't legal is using some type that isn't there at runtime, like

union A {
   int[] a;
   char[] b;
}

A u;

u.a = [1,2];

u.b.length


The compiler will let you do it, but being a union, it will show length == 1 because it was set to an int[], but that's not really correct for a char[].


But the way you did it, initializing to the proper type before accessing it, is allowed.
July 13, 2016
On 07/13/2016 07:01 AM, Adam D. Ruppe wrote:
> On Wednesday, 13 July 2016 at 12:28:57 UTC, zodd wrote:
>> This code works as I expected but I'm unsure that it's correct.
>
> Yes, your code is legal.
>
> What isn't legal is using some type that isn't there at runtime, like
>
> union A {
>     int[] a;
>     char[] b;
> }
>
> A u;
>
> u.a = [1,2];
>
> u.b.length
>
>
> The compiler will let you do it, but being a union, it will show length
> == 1 because it was set to an int[], but that's not really correct for a
> char[].
>
>
> But the way you did it, initializing to the proper type before accessing
> it, is allowed.

Although, in some cases even that assignment operation can do the wrong thing. In general, the left-hand side of the assignment does not hold the invariants of that user-defined type:

import std.stdio;

struct S {
    string fileName;

    S opAssign(S) const {
        writefln("deleting %s", fileName);    // <-- Oops.
        return this;
    }
}

union U {
    S s;
    string file;
}

void main() {
    U u;
    u.file = "important_file.txt";

    // This assignment is executed on an S that is not properly
    // initialized. The operation deletes an unrelated file.
    u.s = S.init;
}


Of course, users of unions must understand how bits of different types are shared and how that can cause trouble.

Ali

July 13, 2016
On Wednesday, 13 July 2016 at 14:01:25 UTC, Adam D. Ruppe wrote:
> Yes, your code is legal.
>
> What isn't legal is using some type that isn't there at runtime, like
>
> union A {
>    int[] a;
>    char[] b;
> }
>
> A u;
>
> u.a = [1,2];
>
> u.b.length
>
>
> The compiler will let you do it, but being a union, it will show length == 1 because it was set to an int[], but that's not really correct for a char[].
>
>
> But the way you did it, initializing to the proper type before accessing it, is allowed.

Thank you!