digitalmars.D.learn - Setting up a final switch from a list
- Salih Dincer (30/32) Aug 07 2023 final switch is not considered safe with enums because it can
- Dom DiSc (9/18) Aug 07 2023 If anything, then this cast is not @safe.
- Nick Treleaven (11/15) Aug 08 2023 I think that casting int to enum is actually memory safe, though
- Steven Schveighoffer (7/24) Aug 08 2023 If you read the integer promotion spec, if both operands are the same
- Nick Treleaven (15/21) Aug 08 2023 OK, thanks.
- Steven Schveighoffer (13/31) Aug 08 2023 It appears that bit shifting doesn't count:
- Nick Treleaven (5/20) Aug 08 2023 Ah, I see.
- kdevel (75/79) Aug 09 2023 Wasn't Cecil concerned with how to ensure at compile time that
- =?UTF-8?Q?Christian_K=c3=b6stlin?= (24/24) Aug 10 2023 I think one part of the original question (now fanished in the nntp
- Salih Dincer (17/42) Mar 28 How can we add all members of an enum type to a list without
- Jonathan M Davis (7/9) Mar 28 As the documentation for EnumMembers explains, you can use
- Salih Dincer (5/15) Mar 29 I guess this falls into metaprogramming. Maybe we should expect
On Wednesday, 2 August 2023 at 18:19:55 UTC, Cecil Ward wrote:Am I right in thinking that final switch can be used to check that all the elements in an enum are handled in cases?final switch is not considered safe with enums because it can take interpolated values, resulting in a runtime error: ```d import std.stdio : writeln; enum alphabet { a, b, c } string lookUp(alphabet value) { with(alphabet) final switch(value) { case a: return "letter a"; break; case b: return "letter b"; break; case c: return "letter c"; break; } } void main() { lookUp(cast(alphabet)0).writeln; // okay alphabet.b.lookUp.writeln; // okay auto abc = alphabet.c; abc.lookUp.writeln; // okay auto abd = cast(alphabet)3; //abd.lookUp.writeln; // runtime-error: /* core.exception.SwitchError onlineapp.d(7): No appropriate switch clause found//*/ } ``` SDB 79
Aug 07 2023
On Monday, 7 August 2023 at 17:08:56 UTC, Salih Dincer wrote:On Wednesday, 2 August 2023 at 18:19:55 UTC, Cecil Ward wrote:If anything, then this cast is not safe. Also arithmetic operations on enums shall never result in enums, but instead will be implicitly cast to integers before the operation. And implicit cast from int to enums don't exist. So in safe code you have to do this cast explicitly and trust it explicitly - and you should not be surprised if trusted code does something bad. That's why you should be extra careful before you trust a cast (or other unsafe operation).Am I right in thinking that final switch can be used to check that all the elements in an enum are handled in cases?final switch is not considered safe with enums because it can take interpolated values, resulting in a runtime error: ```d enum alphabet { a, b, c } auto abd = cast(alphabet)3; ```
Aug 07 2023
On Monday, 7 August 2023 at 17:25:05 UTC, Dom DiSc wrote:If anything, then this cast is not safe.I think that casting int to enum is actually memory safe, though it is not type safe.Also arithmetic operations on enums shall never result in enums, but instead will be implicitly cast to integers before the operation.Unfortunately this is not the case for all operations on enums: ```d auto e = alphabet.a; e |= alphabet.c; // allowed ``` I think bit shifts are allowed too. Due to these, final swift has to always generate a default case. Walter's sum types proposal would provide a type safe enum.
Aug 08 2023
On 8/8/23 4:28 AM, Nick Treleaven wrote:On Monday, 7 August 2023 at 17:25:05 UTC, Dom DiSc wrote:Yes, casting an enum is safe.If anything, then this cast is not safe.I think that casting int to enum is actually memory safe, though it is not type safe.If you read the integer promotion spec, if both operands are the same enum, the result is the same enum. https://dlang.org/spec/type.html#usual-arithmetic-conversions (scroll down to the enum part) -SteveAlso arithmetic operations on enums shall never result in enums, but instead will be implicitly cast to integers before the operation.Unfortunately this is not the case for all operations on enums: ```d auto e = alphabet.a; e |= alphabet.c; // allowed ``` I think bit shifts are allowed too. Due to these, final swift has to always generate a default case.
Aug 08 2023
On Tuesday, 8 August 2023 at 14:06:50 UTC, Steven Schveighoffer wrote:If you read the integer promotion spec, if both operands are the same enum, the result is the same enum. https://dlang.org/spec/type.html#usual-arithmetic-conversions (scroll down to the enum part)OK, thanks. ```d enum E { a, b, c } void f() { E e = E.a; e |= E.c; // same enum, so allowed per spec e = e >> 3; // RHS should be int, which shouldn't convert to E } ``` The spec says:If one operand is an enum and the other is the base type of that enum, the result is the base type.So `e >> 3` should be `int` and the last line of `f` should not compile. But it does. Is the spec wrong or the compiler?
Aug 08 2023
On 8/8/23 12:34 PM, Nick Treleaven wrote:```d enum E { a, b, c } void f() { E e = E.a; e |= E.c; // same enum, so allowed per spec e = e >> 3; // RHS should be int, which shouldn't convert to E } ``` The spec says:It appears that bit shifting doesn't count: ```d auto x = uint.max << 1L; static assert(is(typeof(x)) == uint)); ``` https://dlang.org/spec/expression.html#shift_expressionsIf one operand is an enum and the other is the base type of that enum, the result is the base type.So `e >> 3` should be `int` and the last line of `f` should not compile. But it does. Is the spec wrong or the compiler?The operands must be integral types, and undergo the IntegerPromotions. The result type is the type of the left operand after the promotions. That seems incorrect given the test above. This is a quite old part of the compiler, and a lot of the spec is written to describe the behavior of the compiler. -Steve
Aug 08 2023
On Tuesday, 8 August 2023 at 18:29:42 UTC, Steven Schveighoffer wrote:Ah, I see.It appears that bit shifting doesn't count: ```d auto x = uint.max << 1L; static assert(is(typeof(x)) == uint)); ``` https://dlang.org/spec/expression.html#shift_expressionsIf one operand is an enum and the other is the base type of that enum, the result is the base type.So `e >> 3` should be `int` and the last line of `f` should not compile. But it does. Is the spec wrong or the compiler?Yes, looks like the result is the left operand type without promotions.The operands must be integral types, and undergo the IntegerPromotions. The result type is the type of the left operand after the promotions. That seems incorrect given the test above.
Aug 08 2023
On Monday, 7 August 2023 at 17:08:56 UTC, Salih Dincer wrote:final switch is not considered safe with enums because it can take interpolated values, resulting in a runtime error:Wasn't Cecil concerned with how to ensure at compile time that for all values of an enum there is a handler? I'll post my unsent draft from before the restore here: On Wednesday, 2 August 2023 at 18:19:55 UTC, Cecil Ward wrote:Am I right in thinking that final switch can be used to check that all the elements in an enum are handled in cases?According to [1] this is the case if and only if the switch expression is of that enum type. ``` // compiles with dmd -version=X // missing case qmark if compiled without version import std.stdio; import std.conv; import std.exception; enum terminators_t { percent = '%', colon = ':', qmark = '?' }; int main_ (string [] args) { enforce (args.length == 2, "need one arg"); enforce (args [1].length == 1, "arg must be one character"); auto input = args [1][0].to!terminators_t; final switch (input) { case terminators_t.percent: "PERCENT".writeln; break; case terminators_t.colon: "COLON".writeln; break; version (X) { case terminators_t.qmark: "QUESTION MARK".writeln; break; } } return 0; } int main (string [] args) { try return main_ (args); catch (Exception e) { stderr.writeln (e.msg); return 1; } } ``` But I like it without indentation, switch and break: ``` import std.stdio; import std.exception; void percent () { "PERCENT".writeln; } void colon () { "COLON".writeln; } void qmark () { "QUESTION MARK".writeln; } enum terminatorhandlers = [ // this is implicitly "final" '%' : &percent, ':' : &colon, '?' : &qmark, ]; int main_ (string [] args) { enforce (args.length == 2, "need one arg"); enforce (args [1].length == 1, "arg must be one character"); auto input = args [1] [0]; auto p = input in terminatorhandlers; // switch emulation enforce (p, "unknown terminator " ~ input); (*p) (); // call the registered action return 0; } int main (string [] args) { try return main_ (args); catch (Exception e) { stderr.writeln (e.msg); return 1; } } ``` [1] https://dlang.org/spec/statement.html#final-switch-statement
Aug 09 2023
I think one part of the original question (now fanished in the nntp backup) was how to get all enum members into a list without duplicating code. ```d import std.traits : EnumMembers; import std.stdio : writeln; import std.algorithm : map; import std.conv : to; enum alphabet { a, b, c, d } void main() { writeln(EnumMembers!alphabet); writeln([EnumMembers!alphabet]); writeln([EnumMembers!alphabet].map!(a => "test" ~a.to!string)); } ``` results in ``` abcd [a, b, c, d] ["testa", "testb", "testc", "testd"]``` ```
Aug 10 2023
On Thursday, 10 August 2023 at 08:33:13 UTC, Christian Köstlin wrote:I think one part of the original question (now fanished in the nntp backup) was how to get all enum members into a list without duplicating code. ```d import std.traits : EnumMembers; import std.stdio : writeln; import std.algorithm : map; import std.conv : to; enum alphabet { a, b, c, d } void main() { writeln(EnumMembers!alphabet); writeln([EnumMembers!alphabet]); writeln([EnumMembers!alphabet].map!(a => "test" ~a.to!string)); } ``` results in ```d abcd [a, b, c, d] ["testa", "testb", "testc", "testd"]``` ```How can we add all members of an enum type to a list without duplicating code? I wonder if this is something we'll see soon as the D language feature? In the D programming language, this can be achieved using features provided by the language such as __traits and AliasSeq. For instance, the EnumMembers trait from the std.traits module returns all members of an enum type as a tuple. This tuple contains the enum members in sequence, allowing for iteration over them or conversion into a list. Finally, utilizing these language features to avoid code duplication and write cleaner, more maintainable code is a good practice. Sorry to resurrect this old thread, but what do you think; people living in 2024 ? SDB 79
Mar 28
On Thursday, March 28, 2024 4:21:03 PM MDT Salih Dincer via Digitalmars-d- learn wrote:How can we add all members of an enum type to a list without duplicating code?As the documentation for EnumMembers explains, you can use std.meta.NoDuplicates to strip out duplicates if you want to do something like generate a switch statement from the list of enum members. https://dlang.org/phobos/std_traits.html#EnumMembers - Jonathan M Davis
Mar 28
On Friday, 29 March 2024 at 00:37:21 UTC, Jonathan M Davis wrote:On Thursday, March 28, 2024 4:21:03 PM MDT Salih Dincer via Digitalmars-d- learn wrote:I guess this falls into metaprogramming. Maybe we should expect this possibility from IDEs because I've seen something like this in VScode. All enum members were added automatically. SDB 79How can we add all members of an enum type to a list without duplicating code?As the documentation for EnumMembers explains, you can use std.meta.NoDuplicates to strip out duplicates if you want to do something like generate a switch statement from the list of enum members. https://dlang.org/phobos/std_traits.html#EnumMembers - Jonathan M Davis
Mar 29