I want to test the type of the first object in a signature. The following shows some ways I have found that work. But why does a smart match on a Type (2nd of the 3 tests below) not work? Is there a better way than stringifying and testing for the string equivalent of the Type? (Below is the use case I am working on)
raku -e "sub a( |c ) { say so |c[0].WHAT.raku ~~ /'Rat'/, so |c[0].WHAT ~~ Rat, so |c[0].^name ~~ /'Rat'/ };a(3/2);a(2)"
TrueFalseTrue
FalseFalseFalse
# OUTPUT:
#TrueFalseTrue
#FalseFalseFalse
I am writing a proto sub handle
, and most of the subs have similar signatures, eg. multi sub handle( Pod $node, MyObj $p, Int $level --> Str)
So most of the multi subs do different things depending on what is in $node. However, how to handle cases when the handle
is called with Nil
or a plain string. I am thinking about something like
proto handle(|c) {
if |c[0].^name ~~ /'Str'/ { # code for string }
else { {*} }
}
A better way to introspect ...
In general, a better way to do anything in any programming language is to not introspect if you can avoid it.
In general, in Raku, you can avoid manual introspection. See the section Introspection toward the end of this answer for further discussion.
... a capture
The best tool for getting the functionality that introspection of a capture provides is to use a signature. That's their main purpose in life.
I want to test the type of the first object in a signature
Use signatures:
proto handle(|) {*}
multi handle( Pod $node ) { ... }
multi handle( Str $string ) { ... }
multi handle( Nil ) { ... }
The following shows some ways I have found that work.
While they do what you want, they are essentially ignoring all of Raku's signature features. They reduce the signature to just a binding to the capture as a single structure; and then use manual introspection of that capture in the routine's body.
There's almost always a simpler and better way to do such things using signatures.
why does [
|c[0].WHAT ~~ Rat
, withc[0] == 3/2
] not work?
I'll simplify first, then end up with what your code is doing:
say 3/2 ~~ Rat; # True
say (3/2) ~~ Rat; # True
say (3/2).WHAT ~~ Rat; # True
say |((3/2).WHAT ~~ Rat); # True
say (|(3/2).WHAT) ~~ Rat; # False
say |(3/2).WHAT ~~ Rat; # False
The last case is because |
has a higher precedence than ~~
.
Is there a better way than stringifying and testing for the string equivalent of the Type?
OMG yes.
Use the types, Luke.
(And in your use case, do so using signatures.)
Compared to code that manually introspects incoming data in the body of a routine, appropriate use of signatures will typically:
Read better;
Generate better low-level code;
Be partially or fully evaluated during the compile phase.
If a language and its compiler have addressed a use case by providing a particular feature, such as signatures, then using that feature instead of introspection will generally lead to the above three benefits.
Languages/compilers can be broken into four categories, namely those that:
Do not do or allow any introspection;
Allow the compiler to introspect, but not devs;
Allow both the compiler and devs to introspect, but aim to make it a last resort, at least for devs;
Enable and encourage devs to introspect.
Raku(do) are in the third category. In the context of this SO, signatures are the primary feature that all but eliminates any need for a dev to manually introspect.
You can simply smartmatch to a type:
raku -e "sub a( *@c ) { say @c[0] ~~ Rat };a(3/2);a(2)"
True
False
Also I am using here a slurpy and not a capture, which is another alternative. Any way, with a single argument you're probably better off using type captures
raku -e "sub a( ::T $ ) { say ::T ~~ Rat };a(3/2);a(2)"
True
False
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