Is it possible to define two enums in raku that share the same identifiers?
For example, if I have the following code:
#!/usr/bin/raku
use v6;
enum Color <Red Blue>;
enum TrafficLight <Red Green>;
sub MAIN(
Color:D :c(:$color)!, #= the color
TrafficLight:D :t(:$traffic-light)!, #= the traffic-light
) {
say "Selected $color, Selected $traffic-light"
}
you can see that here, the identifer Red is part of the enum color and the enum TrafficLight.
But when I execute this script, I get the Redeclaration-exception:
$ ./test.p6
Potential difficulties:
Redeclaration of symbol 'Red'
at /home/martin/mnt/release-notes/./scripts/test.p6:5
------> enum TrafficLight <Red Green>⏏;
Usage:
./scripts/test.p6 -c|--color=<Color> (Blue Red) -t|--traffic-light=<TrafficLight> (Green Red)
-c|--color=<Color> (Blue Red) the color
-t|--traffic-light=<TrafficLight> (Green Red) the traffic-light
Interestingly, when I execute this script with the parameters -c=Blue and -t=Red
, the output is that that I would expect:
$ ./test.p6 -c=Blue -t=Red
Potential difficulties:
Redeclaration of symbol 'Red'
at /home/martin/mnt/release-notes/./scripts/test.p6:5
------> enum TrafficLight <Red Green>⏏;
Selected Blue, Selected Red
But when I exeucte this script with the parameters -c=Red and -t=Green
, it doesn't work at all and error-code 2 is returned (showing the help-message).
My questions are now:
namespace
surrounding them?Thanks
1. Two enum names can have same value. For example, in the following C program both 'Failed' and 'Freezed' have same value 0.
No two enum members can have the same name. Each enum member has an associated constant value.
The values assigned to the enum names must be integral constant, i.e., it should not be of other types such string, float, etc. All the enum names must be unique in their scope, i.e., if we define two enum having same scope, then these two enums should have different enum names otherwise compiler will throw an error.
Show activity on this post. I also found the same idea on this question: Two enums have some elements in common, why does this produce an error? Enum names are in global scope, they need to be unique.
The problem is that enum create symbols in their scope. Your code
enum Color <Red Blue>;
enum TrafficLight <Red Green>;
is basically doing
my \Color = Map.new(Red => 0, Blue => 1) does Enumeration;
my \Red := Color<Red>;
my \Blue := Color<Blue>;
my \Traffic-Light = Map.new(Red => 0, Green => 1) does Enumeration;
my \Red := Traffic-Light<Red>;
my \Green := Traffic-Light<Green>;
Thus you can see what generates the warning -- you can't create the symbol twice anymore than you can declare $x
twice in the same scope. Nonetheless, the two enum classes still exist, and can create values from the string "Red". One solution I've used in this case is to create a package and call the enum inside the package: Enum
package Color { enum Enum <Red Blue> }
package TrafficLight { enum Enum <Red Green> }
sub MAIN(
Color::Enum:D :c(:$color )!, #= the color
TrafficLight::Enum:D :t(:$traffic-light)!, #= the traffic-light
) {
say "Selected $color, Selected $traffic-light"
}
If you want to match against the values, then you just say Color::Red
or TrafficLight::Green
, or if you store things in a module so that you can use
, you could still use just Red
or Green
, just not in the same scope. So you could do:
sub MAIN(
Color::Enum:D :c(:$color )!, #= the color
TrafficLight::Enum:D :t(:$traffic-light)!, #= the traffic-light
) {
say "Selected $color, Selected $traffic-light"
{ # new scope
use MyEnums::Color;
given $color {
when Red { ... }
when Green { ... }
}
}
{ # separate new scope
use MyEnums::TrafficLight;
...
}
}
If you only want the enum exported and not the values in the enum, you can use a constant
with a do
block.
constant Color = do {
my enum Color <Red Blue>;
Color
}
constant Traffic-Light = do {
my enum Traffic-Light <Red Green>;
Traffic-Light
}
By doing this you only have to access the values in the enum by its fully qualified name, or by hash access.
say Color::Red.raku;
say Traffic-Light::Red.raku;
say Color::{'Red'}.raku;
say Traffic-Light::{'Red'}.raku;
say Red; # ERROR: Undeclared name: Red
multi foo ( Color $c ){
say "the color $c"
}
multi foo ( Traffic-Light::Red ){
say "stop"
}
multi foo ( Traffic-Light::Green ){
say "go"
}
multi foo ( Str $s ){
samewith Traffic-Light::{$s} // Color::{$s}
}
foo Color::Red; # the color Red
foo Color::Blue; # the color Blue
foo Traffic-Light::Red; # stop
foo Traffic-Light::Green; # go
foo 'Green'; # go
foo 'Red'; # stop
foo 'Blue'; # the color Blue
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With