Re: Enum conversion
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
Re: Enum conversion
On Tue, 2020-04-21 at 15:48 -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. Works for me, you have me convinced. :-) > 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 error QED. Though for converting a ulong to a ubyte, I am assuming to!ubyte(x) is the right tool for the job. […] > pragma(msg, typeof(ZoneNumber.One).stringof); // ZoneNumber Which 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. -- Russel. === Dr Russel Winder t: +44 20 7585 2200 41 Buckmaster Roadm: +44 7770 465 077 London SW11 1EN, UK w: www.russel.org.uk signature.asc Description: This is a digitally signed message part
Re: Enum conversion
On 4/21/20 2:09 PM, tsbockman wrote: 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. 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. -Steve
Re: Enum conversion
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: 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) Hummm… I hadn't got to that one. :-) Why choose that rather than one of the other two? 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 error conversely what is the right way of going the other way: cast(ZoneNumber)1 This 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? typeof(ZoneNumber.One).stringof seemed to return uint. This is what happens for me: enum ZoneNumber : ubyte { One = 1, Two = 2, } pragma(msg, typeof(ZoneNumber.One).stringof); // ZoneNumber -Steve
Re: Enum conversion
On Tue, 2020-04-21 at 18:09 +, tsbockman via Digitalmars-d-learn wrote: > 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. Seems like in this case cast is better than to! use. > > 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. Thanks. It seems to! is de rigueur in this case. -- Russel. === Dr Russel Winder t: +44 20 7585 2200 41 Buckmaster Roadm: +44 7770 465 077 London SW11 1EN, UK w: www.russel.org.uk signature.asc Description: This is a digitally signed message part
Re: Enum conversion
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: > > 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) Hummm… I hadn't got to that one. :-) Why choose that rather than one of the other two? > > > conversely what is the right way of going the other way: > > > > cast(ZoneNumber)1 > > This 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? typeof(ZoneNumber.One).stringof seemed to return uint. > > 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 > } Oooo… I like this, adding ":ubyte" immediately. -- Russel. === Dr Russel Winder t: +44 20 7585 2200 41 Buckmaster Roadm: +44 7770 465 077 London SW11 1EN, UK w: www.russel.org.uk signature.asc Description: This is a digitally signed message part
Re: Enum conversion
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.
Re: Enum conversion
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)1 This 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
Enum conversion
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) conversely what is the right way of going the other way: cast(ZoneNumber)1 to!ZoneNumber(1) I tried: enum ZoneNumber : ubyte { One = 1, Two = 2, } but the members One and Two still seem to be types as int. :-( -- Russel. === Dr Russel Winder t: +44 20 7585 2200 41 Buckmaster Roadm: +44 7770 465 077 London SW11 1EN, UK w: www.russel.org.uk signature.asc Description: This is a digitally signed message part