D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 5515 - std.conv.to for safer enum casts
Summary: std.conv.to for safer enum casts
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: phobos (show other issues)
Version: D2
Hardware: All All
: P2 enhancement
Assignee: No Owner
URL:
Keywords: bootcamp
Depends on:
Blocks:
 
Reported: 2011-02-01 16:22 UTC by bearophile_hugs
Modified: 2018-05-22 09:36 UTC (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description bearophile_hugs 2011-02-01 16:22:32 UTC
If I have an enum of chars, and I have a variable that contains a generic char, I may want to convert the second to an instance of the first one.

A normal cast is enough to do it unsafely, but I'd like to be allowed to use to!() to convert it safely (it may raise an error if it's not among the enum cases).

An example:


import std.conv: to;
enum Foo : char { a = 'A', b = 'B' }
void main() {
    Foo r1 = cast(Foo)'A'; // OK
    Foo r2 = cast(Foo)'X'; // error undetected
    Foo r3 = to!Foo('A');  // OK
    Foo r4 = to!Foo('X');  // error detected
}
Comment 1 bearophile_hugs 2011-08-18 14:51:07 UTC
This enhancement request comes from a handy feature of the Ada language. 

It's not too much hard to implement something similar in D too, with I think an acceptable final user syntax:


import std.traits: EnumMembers, OriginalType, Unqual;
import std.stdio: writeln;

private E[] convertEnum(E, T)(in T[] data) @safe pure nothrow
if (is(E == enum) && is(Unqual!T == OriginalType!Foo)) {
    //assert(__ctfe, "This is a compile-time function only.");

    E[T] dict;
    foreach (member; EnumMembers!E)
        dict[member] = member;

    auto result = new E[data.length];
    foreach (i, item; data)
        result[i] = dict[item];
    return result;
}

enum Foo : char { A='a', B='b', C='c' }

void show(T)(T x) { writeln(x); }

template F(string s) {
    enum F = convertEnum!Foo(s);
}

void main() {
    enum Foo[][] foos = [F!"abcabcabc",
                         F!"cbacbacba"];
    //import std.conv;
    //const Foo[] foos2 = to!(Foo[])("abcabcabc"); // not possible yet
    show(foos); // [[A, B, C, A, B, C, A, B, C],
                //  [C, B, A, C, B, A, C, B, A]]
}


Still, I think safe compile-time Enum conversion and safe run-time Enum conversion is a feature worth folding inside to!().
Comment 2 Andrej Mitrovic 2013-02-17 15:05:24 UTC
Implemented in Issue8143.

*** This issue has been marked as a duplicate of issue 8143 ***
Comment 3 bearophile_hugs 2013-02-17 16:04:00 UTC
(In reply to comment #2)
> Implemented in Issue8143.
> 
> *** This issue has been marked as a duplicate of issue 8143 ***

Given that "Enums with floating-point or string base types are not supported." this is more a WONTFIX :-)
Comment 4 bearophile_hugs 2013-02-17 16:33:03 UTC
But probably this should be supported:


import std.conv: to;
enum Foo : char { A = 'a' }
void main() {
    dchar d = 'a';
    Foo f = to!Foo(d);
}


Currently it gives:

...\dmd2\src\phobos\std\conv.d(274): Error: template std.conv.toImpl does not match any function template declaration. Candidates are:
...


It's useful when you want to write (the argument of this map is a dchar):

import std.conv: to;
import std.algorithm: map;
enum Foo : char { A='a', B='b', C='c' }
void main() {
    auto foos = "abcabcabc".map!(to!Foo)();
}
Comment 5 Andrej Mitrovic 2013-02-17 16:46:53 UTC
(In reply to comment #4)
> But probably this should be supported:
> 
> 
> import std.conv: to;
> enum Foo : char { A = 'a' }
> void main() {
>     dchar d = 'a';
>     Foo f = to!Foo(d);
> }

Ok. Reopening issue.
Comment 6 Dmitry Olshansky 2018-05-22 09:36:08 UTC
import std.conv: to;
import std.algorithm: map;
enum Foo : char { A='a', B='b', C='c' }
void main() {
    auto foos = "abcabcabc".map!(to!Foo)();
}


Compiles today, that was the last of it.