digitalmars.D.learn - Enum conversion
- Russel Winder (25/25) Apr 21 2020 Hi,
- Steven Schveighoffer (19/46) Apr 21 2020 I generally do this:
- Russel Winder (13/68) Apr 21 2020 Hummm=E2=80=A6 I hadn't got to that one. :-)
- Steven Schveighoffer (25/76) Apr 21 2020 1. it's shorter and prettier.
- Russel Winder (19/45) Apr 22 2020 On Tue, 2020-04-21 at 15:48 -0400, Steven Schveighoffer via
- Steven Schveighoffer (8/10) Apr 22 2020 It depends! If you know that the long will fit in a ubyte, by all means
- tsbockman (11/17) Apr 21 2020 Either is acceptable because there is no way that this operation
- Russel Winder (11/34) Apr 21 2020 Seems like in this case cast is better than to! use.
- Steven Schveighoffer (23/37) Apr 21 2020 I just want to correct this and say there isn't a type system
Hi, Given an enum: enum ZoneNumber { One =3D 1, Two =3D 2, } then which of these is the right way of accessing the value? cast(ubyte)ZoneNumber.One to!ubyte(ZoneNumber.One) conversely what is the right way of going the other way: cast(ZoneNumber)1 to!ZoneNumber(1) I tried: enum ZoneNumber : ubyte { One =3D 1, Two =3D 2, } but the members One and Two still seem to be types as int. :-( --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Dr Russel Winder t: +44 20 7585 2200 41 Buckmaster Road m: +44 7770 465 077 London SW11 1EN, UK w: www.russel.org.uk
Apr 21 2020
On 4/21/20 12:03 PM, Russel Winder wrote:Hi, Given an enum: enum ZoneNumber { One = 1, Two = 2, } then which of these is the right way of accessing the value? cast(ubyte)ZoneNumber.One to!ubyte(ZoneNumber.One)I generally do this: ubyte(ZoneNumber.One)conversely what is the right way of going the other way: cast(ZoneNumber)1This will incur zero runtime cost, so I would recommend that.to!ZoneNumber(1)This works too, I think it just does the equivalent of the first, but if not inlined, you will incur some runtime cost.I tried: enum ZoneNumber : ubyte { One = 1, Two = 2, } but the members One and Two still seem to be types as int. :-(They are typed as ZoneNumber, which is a derivative of ubyte. What measurement are you doing to determine that they are int? auto x = ZoneNumber.One; ubyte y = x; // fine If you leave off the :ubyte part, the declaration of y would fail. Similarly, this would fail: enum ZoneMember : ubyte { One = 1, Two = 2, ThreeThousand = 3000, // Error: cannot implicitly convert expression 3000 of type int to ubyte } -Steve
Apr 21 2020
On Tue, 2020-04-21 at 12:59 -0400, Steven Schveighoffer via Digitalmars-d-learn wrote:On 4/21/20 12:03 PM, Russel Winder wrote:Hummm=E2=80=A6 I hadn't got to that one. :-) Why choose that rather than one of the other two?Hi, =20 Given an enum: =20 enum ZoneNumber { One =3D 1, Two =3D 2, } =20 then which of these is the right way of accessing the value? =20 cast(ubyte)ZoneNumber.One to!ubyte(ZoneNumber.One)=20 I generally do this: =20 ubyte(ZoneNumber.One)=20typeof(ZoneNumber.One).stringof seemed to return uint.conversely what is the right way of going the other way: =20 cast(ZoneNumber)1=20 This will incur zero runtime cost, so I would recommend that. =20to!ZoneNumber(1)=20 This works too, I think it just does the equivalent of the first, but if=20 not inlined, you will incur some runtime cost. =20I tried: =20 enum ZoneNumber : ubyte { One =3D 1, Two =3D 2, } =20 but the members One and Two still seem to be types as int. :-(They are typed as ZoneNumber, which is a derivative of ubyte. What=20 measurement are you doing to determine that they are int?=20 auto x =3D ZoneNumber.One; ubyte y =3D x; // fine =20 If you leave off the :ubyte part, the declaration of y would fail. =20 Similarly, this would fail: =20 enum ZoneMember : ubyte { One =3D 1, Two =3D 2, ThreeThousand =3D 3000, // Error: cannot implicitly convert=20 expression 3000 of type int to ubyte }Oooo=E2=80=A6 I like this, adding ":ubyte" immediately. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Dr Russel Winder t: +44 20 7585 2200 41 Buckmaster Road m: +44 7770 465 077 London SW11 1EN, UK w: www.russel.org.uk
Apr 21 2020
On 4/21/20 3:00 PM, Russel Winder wrote:On Tue, 2020-04-21 at 12:59 -0400, Steven Schveighoffer via Digitalmars-d-learn wrote:1. it's shorter and prettier. 2. No cast (I avoid using cast whenever I can). 3. No gotcha type conversions. e.g. for point 3: enum ZoneMember { // : int One = 1, Two = 2, ReallyBig = 4567, } auto b1 = ubyte(ZoneNumber.One); // 1 (compiler uses VRP to make this work) auto b2 = ubyte(ZoneNumber.ReallyBig); // Compiler error vs. auto b1 = cast(ubyte)ZoneNumber.One; // 1 auto b2 = cast(ubyte)ZoneNumber.ReallyBig; // b2 == 215 (truncated) vs. auto b1 = to!ubyte(ZoneNumber.One); // 1 auto b2 = to!ubyte(ZoneNumber.ReallyBig); // runtime errorOn 4/21/20 12:03 PM, Russel Winder wrote:Hummm… I hadn't got to that one. :-) Why choose that rather than one of the other two?Hi, Given an enum: enum ZoneNumber { One = 1, Two = 2, } then which of these is the right way of accessing the value? cast(ubyte)ZoneNumber.One to!ubyte(ZoneNumber.One)I generally do this: ubyte(ZoneNumber.One)This is what happens for me: enum ZoneNumber : ubyte { One = 1, Two = 2, } pragma(msg, typeof(ZoneNumber.One).stringof); // ZoneNumber -Stevetypeof(ZoneNumber.One).stringof seemed to return uint.conversely what is the right way of going the other way: cast(ZoneNumber)1This will incur zero runtime cost, so I would recommend that.to!ZoneNumber(1)This works too, I think it just does the equivalent of the first, but if not inlined, you will incur some runtime cost.I tried: enum ZoneNumber : ubyte { One = 1, Two = 2, } but the members One and Two still seem to be types as int. :-(They are typed as ZoneNumber, which is a derivative of ubyte. What measurement are you doing to determine that they are int?
Apr 21 2020
On Tue, 2020-04-21 at 15:48 -0400, Steven Schveighoffer via Digitalmars-d-learn wrote: [=E2=80=A6]=20 1. it's shorter and prettier. 2. No cast (I avoid using cast whenever I can). 3. No gotcha type conversions.Works for me, you have me convinced. :-)e.g. for point 3: =20 enum ZoneMember { // : int One =3D 1, Two =3D 2, ReallyBig =3D 4567, } =20 auto b1 =3D ubyte(ZoneNumber.One); // 1 (compiler uses VRP to make this work) auto b2 =3D ubyte(ZoneNumber.ReallyBig); // Compiler error =20 vs. =20 auto b1 =3D cast(ubyte)ZoneNumber.One; // 1 auto b2 =3D cast(ubyte)ZoneNumber.ReallyBig; // b2 =3D=3D 215 (truncated) =20 vs. =20 auto b1 =3D to!ubyte(ZoneNumber.One); // 1 auto b2 =3D to!ubyte(ZoneNumber.ReallyBig); // runtime errorQED. Though for converting a ulong to a ubyte, I am assuming to!ubyte(x) is the right tool for the job. [=E2=80=A6]pragma(msg, typeof(ZoneNumber.One).stringof); // ZoneNumberWhich is as it should be really. I was clearly having a mental aberration. Anyway, the probem is now solved! :-) Thanks for your input, much appreciated. =20 --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Dr Russel Winder t: +44 20 7585 2200 41 Buckmaster Road m: +44 7770 465 077 London SW11 1EN, UK w: www.russel.org.uk
Apr 22 2020
On 4/22/20 6:36 AM, Russel Winder wrote:Though for converting a ulong to a ubyte, I am assuming to!ubyte(x) is the right tool for the job.It depends! If you know that the long will fit in a ubyte, by all means just use a cast. It's the fastest option. If you have no idea the value of the long, but it's *supposed* to fit into a ubyte, use to if you want an exception for those outside the range. And if you don't care, and just want a ubyte, use a cast. But the compiler isn't going to accept ubyte(someLong). -Steve
Apr 22 2020
On Tuesday, 21 April 2020 at 16:03:20 UTC, Russel Winder wrote:then which of these is the right way of accessing the value? cast(ubyte)ZoneNumber.One to!ubyte(ZoneNumber.One)Either is acceptable because there is no way that this operation can fail. Using a naked `cast` makes less work for the compiler and performs optimally with or without inlining, though.conversely what is the right way of going the other way: cast(ZoneNumber)1 to!ZoneNumber(1)Use `to` except where you can gaurantee that the input value maps to a valid enum member, because `cast` does not check your work: writeln(cast(ZoneNumber)17); // breaks the type system writeln(to!ZoneNumber(17)); // throws a ConvException: Value (17) does not match any member value of enum 'ZoneNumber' So, `cast` is faster, but unsafe. `to` is slower, but protects the enum's invariant.
Apr 21 2020
On Tue, 2020-04-21 at 18:09 +0000, tsbockman via Digitalmars-d-learn wrote:On Tuesday, 21 April 2020 at 16:03:20 UTC, Russel Winder wrote:Seems like in this case cast is better than to! use.then which of these is the right way of accessing the value? =20 cast(ubyte)ZoneNumber.One to!ubyte(ZoneNumber.One)=20 Either is acceptable because there is no way that this operation=20 can fail. Using a naked `cast` makes less work for the compiler=20 and performs optimally with or without inlining, though.Thanks. It seems to! is de rigueur in this case. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Dr Russel Winder t: +44 20 7585 2200 41 Buckmaster Road m: +44 7770 465 077 London SW11 1EN, UK w: www.russel.org.ukconversely what is the right way of going the other way: =20 cast(ZoneNumber)1 to!ZoneNumber(1)=20 Use `to` except where you can gaurantee that the input value maps=20 to a valid enum member, because `cast` does not check your work: =20 writeln(cast(ZoneNumber)17); // breaks the type system writeln(to!ZoneNumber(17)); // throws a ConvException: Value=20 (17) does not match any member value of enum 'ZoneNumber' =20 So, `cast` is faster, but unsafe. `to` is slower, but protects=20 the enum's invariant.
Apr 21 2020
On 4/21/20 2:09 PM, tsbockman wrote:I just want to correct this and say there isn't a type system requirement for the enum to be only one of the selected values, even in safe code. e.g.: enum flags { one = 1, two = 2, } flags f = flags.one | flags.two; // ok ++f; // ok also In essence, an enum acts as a derived type with named constants. Also, there is one situation where you can't use to -- a string-based enum: enum sym : string { s = "s value", y = "y value" } auto a = cast(sym)"s value"; // ok assert(a == sym.s); auto b = to!sym("s value"); // runtime error This is because to!someEnum(string) is specialized to look at the enum names only, not the values. -Steveconversely what is the right way of going the other way: cast(ZoneNumber)1 to!ZoneNumber(1)Use `to` except where you can gaurantee that the input value maps to a valid enum member, because `cast` does not check your work: writeln(cast(ZoneNumber)17); // breaks the type system writeln(to!ZoneNumber(17)); // throws a ConvException: Value (17) does not match any member value of enum 'ZoneNumber' So, `cast` is faster, but unsafe. `to` is slower, but protects the enum's invariant.
Apr 21 2020