Todd
Todd

Reputation: 976

perl6/raku: how to I restrict the values allowed in a variable?

Perl6/Raku

I would like to create a sub were only certain values are allowed to be passed to it. And not passing the allowed value will create a checker error (perl6 -c).

How do I do this?

Many thanks, -T

Hi Raiph,

In my WinPopUps module, I used the "where" method because it tells the user at a glance what the allowed values are. I love it! It is all about maintainability! (By the way, the following is the monster your created!)

sub WinPopUp( Str $TitleStr, 
              Str $MessageStr,
              Str $Icons where   * ~~ "Exclamation"             |
                                      "Warning"                 |
                                      "Information"             |
                                      "Asterisk"                |
                                      "Question"                |
                                      "Stop"                    |
                                      "Error"                   |
                                      "Hand",
              Str $Buttons where * ~~ "AbortRetryIgnore"        | 
                                      "CancelTryAgainContinue"  |
                                      "Help"                    |
                                      "Ok"                      |
                                      "OkCancel"                |
                                      "RetryCancel"             |
                                      "YesNo"                   |
                                      "YesNoCancel" ) 
              is export( :WinPopUp ) {

Thank you for the help! -T

Let me know if you want the whole module and where to post it

Upvotes: 7

Views: 219

Answers (2)

Holli
Holli

Reputation: 5072

You can simply add a where condition on the values

sub foo( Int $binary where * ~~ 0|1 ) { ... }

The where condition can be an arbitrary code block ( or even a sub I believe ).

If you need the condition multiple times you can create a subset.

subset BinaryInt of Int where * ~~ 0|1;

and subsequently use that in the signature

sub foo( BinaryInt $binary ) { ... }

Note, this isn't just limited to subroutine signatures. The constraints/conditions are enforced everywhere

my BinaryInt $i = 0; 
$i++; 
$i++;
# -> Type check failed in assignment to $i; expected BinaryInt but got Int (2)

You can also have subsets of subsets:

subset FalseBinaryInt of BinaryInt where not *;
my FalseBinaryInt $i = 0; 
$i++; 
# -> Type check failed in assignment to $i; expected FalseBinaryInt but got Int (1)

Edit: JJ down there is right. In this case an enumeration is useful. This

sub WinPopUp( Str $TitleStr, 
              Str $MessageStr,
              MessageBoxIcons $Icons where   * ~~ Exclamation |
                                                  Information |
              ...

Paired with an enumeration like

enum MessageBoxIcons is export {
    Exclamation => 0x00000030,
    Information => 0x00000040,
    ...
}

protects you from random typos, as enum members are symbols, and if you mispell one, the compiler will catch it. Also you don't have to look up the values to feed into MessageBoxW (which is what you are doing I assume).

Speaking of MessageBoxW, I would call your sub message-box (in Raku we tend to use CamelCase only for Classes and Types and stuff) just to stay consistent with MessageBoxW

Upvotes: 12

jjmerelo
jjmerelo

Reputation: 23527

In your case, it would be probably the best to use enums:

enum Icons <Exclamation Warning Information>;
sub pop-up( Icons $icon ) { $icon}; 
say pop-up( Information ); # OUTPUT: «Information␤»

However, you're using Str already for some reason, so it might be better to use subsets:

subset Icons of Str where * eq any <Exclamation Warning Information>;
sub pop-up( Icons $icon ) { $icon};
say pop-up( "Information" ); 

These have already been mentioned in Holli's answer, although only "if you are going to use them several times". I would define a subset even if you're using it only one. It's safer, and also clearer, as well as testable.

Upvotes: 0

Related Questions