www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Converting all enum members to a string fails with version 2.0.72.0

reply Stefan <StefanLiebig web.de> writes:
Before 2.0.72.0:

import std.algorithm : map, joiner;
import std.uni : toUpper;
import std.traits : EnumMembers;
import std.stdio : writeln;
import std.conv: to;

private enum Color : string {
     RED = "red",
     BLUE = "blue",
     YELLOW = "yellow"
}


void main(string[] args) {
     writeln( [ EnumMembers!Color ].map!( toUpper ).joiner( ", " 
).to!string );
}

printed:
RED, BLUE, YELLOW

Now I got the following compiler error:
C:\develop\dmd-2.072.0\windows\bin\..\..\src\phobos\std\uni.d(8142,16): Error:
cannot implicitly convert expression (result.data()) of type string to Color
C:\develop\dmd-2.072.0\windows\bin\..\..\src\phobos\std\uni.d(9030,51): Error:
template instance std.uni.toCase!(toUpperIndex, 1051, toUpperTab, toUpper,
Color) error instantiating
C:\develop\dmd-2.072.0\windows\bin\..\..\src\phobos\std\algorithm\
teration.d(593,19):        instantiated from here: toUpper!(Color)
C:\develop\dmd-2.072.0\windows\bin\..\..\src\phobos\std\algorithm\
teration.d(488,16):        instantiated from here: MapResult!(toUpper, Color[])
source\enums\enums.d(24,35):        instantiated from here: 
map!(Color[])
source\enums\enums.d(24,58): Error: template 
std.algorithm.iteration.joiner cannot deduce function from 
argument types !()(MapResult!(toUpper, Color[]), string), 
candidates are:
C:\develop\dmd-2.072.0\windows\bin\..\..\src\phobos\std\algorithm\
teration.d(2050,6):        std.algorithm.iteration.joiner(RoR, Separator)(RoR
r, Separator sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) &&
isForwardRange!Separator && is(ElementType!Separator :
ElementType!(ElementType!RoR)))
C:\develop\dmd-2.072.0\windows\bin\..\..\src\phobos\std\algorithm\
teration.d(2333,6):        std.algorithm.iteration.joiner(RoR)(RoR r) if
(isInputRange!RoR && isInputRange!(ElementType!RoR))
dmd failed with exit code 1.

Any idea how to fix it?

Thanks,
Stefan
Nov 21 2016
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Monday, November 21, 2016 17:01:56 Stefan via Digitalmars-d-learn wrote:
 Before 2.0.72.0:

 import std.algorithm : map, joiner;
 import std.uni : toUpper;
 import std.traits : EnumMembers;
 import std.stdio : writeln;
 import std.conv: to;

 private enum Color : string {
      RED = "red",
      BLUE = "blue",
      YELLOW = "yellow"
 }


 void main(string[] args) {
      writeln( [ EnumMembers!Color ].map!( toUpper ).joiner( ", "
 ).to!string );
 }

 printed:
 RED, BLUE, YELLOW

 Now I got the following compiler error:
 C:\develop\dmd-2.072.0\windows\bin\..\..\src\phobos\std\uni.d(8142,16):
 Error: cannot implicitly convert expression (result.data()) of type
 string to Color
 C:\develop\dmd-2.072.0\windows\bin\..\..\src\phobos\std\uni.d(9030,51):
 Error: template instance std.uni.toCase!(toUpperIndex, 1051, toUpperTab,
 toUpper, Color) error instantiating
 C:\develop\dmd-2.072.0\windows\bin\..\..\src\phobos\std\algorithm\iterati
 on.d(593,19):        instantiated from here: toUpper!(Color)
 C:\develop\dmd-2.072.0\windows\bin\..\..\src\phobos\std\algorithm\iterati
 on.d(488,16):        instantiated from here: MapResult!(toUpper, Color[])
 source\enums\enums.d(24,35):        instantiated from here:
 map!(Color[])
 source\enums\enums.d(24,58): Error: template
 std.algorithm.iteration.joiner cannot deduce function from
 argument types !()(MapResult!(toUpper, Color[]), string),
 candidates are:
 C:\develop\dmd-2.072.0\windows\bin\..\..\src\phobos\std\algorithm\iteratio
 n.d(2050,6):        std.algorithm.iteration.joiner(RoR, Separator)(RoR r,
 Separator sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) &&
 isForwardRange!Separator && is(ElementType!Separator :
 ElementType!(ElementType!RoR)))
 C:\develop\dmd-2.072.0\windows\bin\..\..\src\phobos\std\algorithm\iterati
 on.d(2333,6):        std.algorithm.iteration.joiner(RoR)(RoR r) if
 (isInputRange!RoR && isInputRange!(ElementType!RoR)) dmd failed with exit
 code 1.

 Any idea how to fix it?
Casting [EnumMembers!Color] to string[] will probably do it as would using toUpper!string instead of toUpper. I think that the problem has to do with Color not being an actual range, but it passes isSomeString, resulting in a an ugly situation where the code basically assumes that it's dealing with a string when it isn't really, and the code doesn't actually work with an enum. Prior to 2.072.0, there was an overload for toUpper that took string as an optimization but that inadvertently meant that types that implicitly converted to strings worked with it and were converted to string, whereas with 2.072.0, they now have to pass isSomeString. In the case of a struct that implicitly converts to string or a static array of characters, it would now simply fails the template constraint and fail to compile, whereas for an enum with a base type of string, it's in this weird in between land where it passes isSomeString but really needs to actually be converted to string to work as a range. So, instead of failing the template constraint, it hits an error inside of the std.uni stuff. I think that the change is getting reverted for 2.072.1, because it broke existing code, but for now at least, enums aren't going to work with toUpper or toLower. Unfortunately, templated code that deals with strings needs to be _really_ careful about how it deals with enums with a base type of string, because they pass isSomeString but aren't actually strings (which is great for code that doesn't use the range API but falls flat on its face for code that does use the range API). Static arrays and structs which implicitly convert to strings have the same problem, but at least they don't pass isSomeString. In general, any type which implicitly converts to another type really needs to have that coversion forced with generic code that wants the converted type; otherwise, it's going to have a tendency to fall flat on its face. - Jonathan M Davis
Nov 21 2016
next sibling parent Basile B. <b2.temp gmx.com> writes:
On Monday, 21 November 2016 at 17:26:37 UTC, Jonathan M Davis 
wrote:
 On Monday, November 21, 2016 17:01:56 Stefan via 
 Digitalmars-d-learn wrote:
 [...]
[...] there was an overload for toUpper that took string as an optimization but that inadvertently meant that types that implicitly converted to strings worked with it and were converted to string, whereas with 2.072.0, they now have to pass isSomeString. [...] I think that the change is getting reverted for 2.072.1, because it broke existing code, but for now at least, enums aren't going to work with toUpper or toLower. [...]
Indeed: https://issues.dlang.org/show_bug.cgi?id=16663
Nov 21 2016
prev sibling parent reply Stefan <StefanLiebig web.de> writes:
On Monday, 21 November 2016 at 17:26:37 UTC, Jonathan M Davis 
wrote:
 [...]
Thanks Jonathan for the explanation. The cast works fine but feels "unsafe". I will wait for the next version. Stefan
Nov 21 2016
parent Stefan <stefanliebig web.de> writes:
On Monday, 21 November 2016 at 18:53:59 UTC, Stefan wrote:
 On Monday, 21 November 2016 at 17:26:37 UTC, Jonathan M Davis 
 wrote:
 [...]
Thanks Jonathan for the explanation. The cast works fine but feels "unsafe". I will wait for the next version. Stefan
Version D 2.072.1 Beta fixed my problem.
Nov 29 2016