my previous original programme to show week number of given date looks like
multi sub MAIN ( Int $year, Int $month, Int $day ) {
say Date.new( :$year, :$month, :$day ).week-number();
}
If we don't use any data type in the parameter, you need to make sure all variables are suitable for the function. if there are many functions, it might be frustrating!!
It is safe to believe that type checking at "entrance" of a programme (which especially needs I/O or user input) is a great way to make the routines inside the function is easy to implement.
But wait... are year, month and day Integer exactly??
USING subset
raku provide a way to make your own type from existing one.
subset Natural of UInt where 0 < *;
We just create a Natural number type from existing UInt (Unsigned Int)
Year is okay with just Natural type. but let's make others.
subset Month of Natural where * < 13;
subset Day of Natural where * < 32;
Does it sound correct? some might say "day is depends on the Month value".
but which is sadly up to your routines inside the function or Library which you are using.
So now our new MAIN function looks like
multi sub MAIN ( Natural $year, Month $month, Day $day ) {
say Date.new( :$year, :$month, :$day ).week-number();
}
and my full programme looks like
subset Natural of UInt where 0 < *;
subset Month of Natural where * < 13;
subset Day of Natural where * < 32;
sub cutoff-last-two-chars ( Str $i is rw # warning: side effects
where $i.chars > 1 ) {
my $last-two-chars := $i.substr-rw( *-2, * );
my $ret = $last-two-chars;
$last-two-chars = ""; # remove them from the string
return $ret;
}
multi sub MAIN ( Natural \yyyymmdd ) {
my $yyyymmdd = yyyymmdd;
my UInt ( $year, $month, $day );
$day = (cutoff-last-two-chars $yyyymmdd).UInt;
$month = (cutoff-last-two-chars $yyyymmdd).UInt;
$year = $yyyymmdd.UInt;
samewith( $year, $month, $day );
}
multi sub MAIN ( Natural $year, Month $month, Day $day ) {
say Date.new( :$year, :$month, :$day ).week-number();
}
One more thing : Don't be too strict
the way to get last two digit from user input has been slightly changed. but look at the signature:
sub cutoff-last-two-chars ( Str $i is rw # warning: side effects
where $i.chars > 1 ) {
...
"$i.chars > 1" check the $i has two or more than 2 characters so that we can get expected result from a string. however this could be resulted in runtime exception:
let's check in Raku's REPL
> my $test = "804";
804
> cutoff-last-two-chars($test)
04
> cutoff-last-two-chars($test)
Constraint type check failed in binding to parameter '$i'; expected anonymous constraint to be met but got Str ("8")
in sub cutoff-last-two-chars at <unknown file> line 1
in block <unit> at <unknown file> line 1
>
you can see the errors which is unexpected because we only wanted to make the function perfect and safe but we also make our "programme itself" unsafe in the end.
You can check each variable before calling cutoff-last-two-chars to make the programme detect problem and finish it nicely. but.. this make programme only more complicated.
So there is another solution for this. As I mentioned before, check user input at the entrance of the programme.
multi sub MAIN ( Natural \yyyymmdd where yyyymmdd > 10100 ) {
my $yyyymmdd = yyyymmdd;
...
and you can remove the constraint from the cutoff-last-two-digits function or keep. It depends on your decision. but IMHO in script language world, less constraints means more performance!
So, please don't be too strict!
That's all for today! 🤩
Top comments (0)