On Thursday, 17 June 2021 at 21:41:28 UTC, Steven Schveighoffer wrote:
> A final switch on an enum complains if you don't handle all the enum's cases. I like this feature.
However, sometimes the data I'm switching on is coming from elsewhere (i.e. a user), and while I want to enforce that the data is valid (it's one of the enum values), I don't want to crash the program if the incoming value is not correct. But final switch doesn't let me declare a default case (to throw an exception instead).
If I use a non-final switch, then my code might forget to handle one of the cases.
Oh, and to throw a monkey wrench in here, the value is a string, not an integer. So I can't use std.conv.to to verify the enum is valid (plus, then I'm running a switch twice).
Any ideas on better ways to handle this?
-Steve
Well, if you receive an enum
that have an out of bounds value, your problem lies in the caller, not the callee. You're breaking the most fundamental promise of a type, that is, the values it can take. And you obviously also break any @safe
function by feeding it this value.
So instead of thinking in terms of enum
, I would say, think in them of the value, and generate the switch:
SWITCH: switch (myRawValue)
{
static foreach (EV; NoDuplicates!(EnumMembers!MyEnum))
{
case EV:
// Handle;
break SWITCH;
}
default:
throw new Exception("Invalid value: " ~ myRawValue);
}
Note that this can be encapsulated in its own function, like validateEnum (EnumType) (BaseType!EnumType value)
(not sure if we have a BaseType
template, but you get the point).