Re: Enum conversion

2020-04-22 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2020-04-22 Thread Russel Winder via Digitalmars-d-learn
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

2020-04-21 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2020-04-21 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2020-04-21 Thread Russel Winder via Digitalmars-d-learn
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

2020-04-21 Thread Russel Winder via Digitalmars-d-learn
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

2020-04-21 Thread tsbockman via Digitalmars-d-learn

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

2020-04-21 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2020-04-21 Thread Russel Winder via Digitalmars-d-learn
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