Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A better way to introspect a capture

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 { {*} }
}
like image 369
Richard Hainsworth Avatar asked Jul 01 '20 09:07

Richard Hainsworth


2 Answers

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, with c[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.)

Introspection

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:

  1. Do not do or allow any introspection;

  2. Allow the compiler to introspect, but not devs;

  3. Allow both the compiler and devs to introspect, but aim to make it a last resort, at least for devs;

  4. 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.

like image 154
raiph Avatar answered Oct 20 '22 08:10

raiph


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
like image 44
jjmerelo Avatar answered Oct 20 '22 07:10

jjmerelo