Jump to page: 1 2
Thread overview
Tuple enumeration without integers or strings
Jan 01
Rekel
Jan 02
Paul
Jan 02
frame
Jan 02
Paul
Jan 03
Paul
Jan 03
frame
Jan 03
Paul
Jan 03
frame
Jan 03
Paul
January 01
I seem to have hit a bit of a wall when comparing D enums to Java enums.
Of course the latter is just a fancy class, though it'd be nice to see partially equivalent usefulness regardless.

For example, as soon as non-integer, non-string values are given to enums things get messy for me when using switch cases, I haven't yet found a satisfying way of doing this.
Note the reason I'm using tuples is to somehow replicate the way java enumerals can contain several member variables, which tends to be very useful.

Something along the lines of the following is what i'd like to achieve;
> alias Direction = Tuple!(byte, "x", byte, "y");
> enum Wind {N = Direction(0, 1) ... etc}
> ...
> void some_function(Wind w) {
>     switch (w) {
>         case Wind.N:
>             ... etc
>             break;
>         ... etc
>         default:
>             assert(0);
>     }
> }

One thing that might have worked would have been an equivalent of java's "ordinal", though from what I've found D doesn't seem to have something equivalent to this?
(I'd prefer not to have a seperate tuple member purely for ordinality, and dropping enumerals altogether also seems like a waste)
January 02
It seems w.to!string works in conjunction with Wind.N.stringof, though I wonder about the efficiency/wastefulness of this method.
Sadly this also leads to very funny behavior when some of the enums have the same value, as to!string(Enum) will yield the name of the first of these enums having the same values.

> alias Thing = Tuple!(int, int);
> enum Enum {
>     A = Thing(0, 1),
>     B = Thing(0, 2),
>     C = Thing(0, 2)
> }
> void main(){
>     Enum.C.to!string.writeln;
> }

For example, the code above will print 'B' (I'm slightly curious how & why std.conv uses the Enum name when converting to string, instead of using the value, especially since I didn't see this pitfall coming partly due to this)

So this neither seems a satisfiable solution to me :/
January 02
On Saturday, 2 January 2021 at 00:57:48 UTC, Paul wrote:
> So this neither seems a satisfiable solution to me :/

Couldn't you just use Wind.N.hashOf and a custom format() expression for string-representation?


January 02
On Friday, 1 January 2021 at 23:14:43 UTC, Rekel wrote:
> I seem to have hit a bit of a wall when comparing D enums to Java enums.
> Of course the latter is just a fancy class, though it'd be nice to see partially equivalent usefulness regardless.
>
> For example, as soon as non-integer, non-string values are given to enums things get messy for me when using switch cases, I haven't yet found a satisfying way of doing this.

D's switch statement only works on strings and integers. For more complex values, the easiest thing is to just use an if-else chain.

If you really want to use a switch statement, you can do it by defining a function that maps each of your enum values to a unique integer; for example:

enum Wind { ... }

size_t index(Wind w)
{
    if (w = Wind.N) return 0;
    // etc.
}

void someFunction(Wind w)
{
    switch(w.index) {
        case Wind.N.index: // uses CTFE
            // ...
            break;
        // etc.
        default: assert(0);
    }
}
January 02
On Saturday, 2 January 2021 at 03:20:29 UTC, Paul Backus wrote:
> D's switch statement only works on strings and integers. For more complex values, the easiest thing is to just use an if-else chain.
>
> If you really want to use a switch statement, you can do it by defining a function that maps each of your enum values to a unique integer; for example:

Im afraid that would still result in issues when duplicate enum vlues are at play right?
(This issue would maybe warrant a compile time warning imho)
January 02
On Saturday, 2 January 2021 at 21:41:34 UTC, Paul wrote:
> On Saturday, 2 January 2021 at 03:20:29 UTC, Paul Backus wrote:
>> D's switch statement only works on strings and integers. For more complex values, the easiest thing is to just use an if-else chain.
>>
>> If you really want to use a switch statement, you can do it by defining a function that maps each of your enum values to a unique integer; for example:
>
> Im afraid that would still result in issues when duplicate enum vlues are at play right?

Yes, but this will be true of any approach you choose. If two enum members have exactly the same value, there is no way to distinguish between them, either at compile time or at runtime.
January 03
On Saturday, 2 January 2021 at 21:48:04 UTC, Paul Backus wrote:
> Yes, but this will be true of any approach you choose. If two enum members have exactly the same value, there is no way to distinguish between them, either at compile time or at runtime.

Oh I see, thanks!
A bit of a bummer as I guess that means you're pretty much required to use an additional seperate structure like an array or map/associative array, the latter making the use of an enum instead of string names slightly pointless in this scenario, thank you nontheless 😅.
January 03
On Sunday, 3 January 2021 at 01:15:56 UTC, Paul wrote:
> On Saturday, 2 January 2021 at 21:48:04 UTC, Paul Backus wrote:
>> Yes, but this will be true of any approach you choose. If two enum members have exactly the same value, there is no way to distinguish between them, either at compile time or at runtime.
>
> Oh I see, thanks!
> A bit of a bummer as I guess that means you're pretty much required to use an additional seperate structure like an array or map/associative array, the latter making the use of an enum instead of string names slightly pointless in this scenario, thank you nontheless 😅.

Besides the problem with equal values, what's wrong with that:

alias Thing = Tuple!(int, int);
enum Wind {
    A = Thing(0, 1),
    B = Thing(0, 2),
    C = Thing(0, 2)
}

void some_function(Wind w) {
    switch (w.hashOf) {
    case Wind.B.hashOf:
        break;

    default:
        assert(0);
    }
}

void main() {
    some_function(Wind.B);
    writefln("%d%d", Wind.C.expand);
}
January 03
On Sunday, 3 January 2021 at 02:17:43 UTC, frame wrote:
> Besides the problem with equal values, what's wrong with that:
>
> alias Thing = Tuple!(int, int);
> enum Wind {
>     A = Thing(0, 1),
>     B = Thing(0, 2),
>     C = Thing(0, 2)
> }
>
> void some_function(Wind w) {
>     switch (w.hashOf) {
>     case Wind.B.hashOf:
>         break;
>
>     default:
>         assert(0);
>     }
> }
>
> void main() {
>     some_function(Wind.B);
>     writefln("%d%d", Wind.C.expand);
> }

I haven't used hashOf before, though assuming no  equal values, which I generally wouldn't do, I take it this is reliable? I haven't tried it before, and I dont know how to effectively compare it to using 'switch(w.to!string)' & 'case Wind.B.stringof' (regarding speed/reliability).
January 03
On Sunday, 3 January 2021 at 02:41:12 UTC, Paul wrote:
>
> I haven't used hashOf before, though assuming no  equal values, which I generally wouldn't do, I take it this is reliable? I haven't tried it before, and I dont know how to effectively compare it to using 'switch(w.to!string)' & 'case Wind.B.stringof' (regarding speed/reliability).

hashOf is not guaranteed to produce unique values, so I would not advise using it here.

to!string is expensive both at compile time (requires a lot of template instantiations) and runtime (needs to allocate memory for the string). It will work if you need to hack something together quickly, but I would not recommend it for "serious" code.
« First   ‹ Prev
1 2