13

I know that this will not work, since I tried it:

if $r ~~ BearingTrue || CompassAdj || CourseAdj { nextsame };

But - is there a neat, concise and legible way to do multiple Type smart matches on one line rather than have to expand to a given/when or if/else construct?

librasteve
  • 6,832
  • 8
  • 30
  • Hi p6steve I've tried your code and @Scimon_Proctor's answer below, but I keep getting "Undeclared names" errors for BearingTrue, etc. Any hints? – jubilatious1 Feb 02 '21 at 16:26
  • 1
    hi @jubilatious1 - my code snippet is in the body of a raku module, so you will need to install the module with zef and to use it with use before those names are available in your code. Also, while the '|' junction worked fine I realised that my code would be cleaner by testing for the one thing it should not be, not the three things it should be... see my new "Answer" below or the final version. – librasteve Feb 03 '21 at 17:17

2 Answers2

15

Have you tried :

if $r ~~ BearingTrue | CompassAdj | CourseAdj { nextsame };

This should give you an Any Junction that with then match OK.

Scimon Proctor
  • 4,558
  • 23
  • 22
  • hi @scimon - this does the trick (I had tried .any ... I must have misapplied and that put me off the scent) - slightly embarrassing – librasteve Jan 15 '21 at 19:53
  • 1
    @p6steve The reason it might've not worked is because `<...>` creates a `List` of `Str`s. Thus you were smartmatching againts strings, instead of types. `if $r ~~ (BearingTrue, CompassAdj, CourseAdj).any { nextsame }` should work fine. Btw this seems like a nice opportunity to use `if`'s statement modifier version: `nextsame if $r ~~ (BearingTrue, CompassAdj, CourseAdj).any;` – uzluisf Feb 04 '21 at 16:22
1

This Answer is to let me address the comment from @jubilatious1 a bit more clearly.

I am working on a new raku module, see line 225 ish here Physics::Navigation

For illustrative purposes, the code now looks like this...

class BearingTrue { ...}
class BearingMag  { ...}

sub err-msg { die "Can't mix BearingTrue and BearingMag for add/subtract!" }

class BearingTrue is Bearing is export {

    multi method compass { <T> }                        #get compass

    multi method compass( Str $_ ) {                    #set compass
        die "BearingTrue compass must be <T>" unless $_ eq <T> }

    method M {                                          #coerce to BearingMag
        my $nv = $.value + ( +$variation + +$deviation );
        BearingMag.new( value => $nv, compass => <M> )
    }

    #| can't mix unless BearingMag 
    multi method add( BearingMag ) { err-msg }
    multi method subtract( BearingMag ) { err-msg }
}

So I decided to recast the code to use multi-method add and subtract to check type matches to prevent a lost mariner from adding a magnetic bearing to a true one. I feel that this is cleaner even than Scimon's great answer, since in that instance, my method was accepting all child types of Bearing and then using an if statement to detect a type error.

You are welcome to go...

zef install https://github.com/p6steve/raku-Physics-Navigation.git

then follow the example at the top of bin/synopsis-navigation.raku to use the module and make the various classes available in your own code.

If you are just keen to see how the pieces fit then I suggest writing your own simple classes on similar lines and working through the examples in books such as ThinkRaku chapter 12. I recommend this for the clarity and level of information and it treats inheritance and roles equally.

I am confident that others will feel my code style is over-reliant on inheritance. I feel that since a magnetic-bearing is strictly a derived concept from a bearing-in-general that this is right for my code - but roles and composition is less restrictive and provides similar encapsulation with better maintainability.

librasteve
  • 6,832
  • 8
  • 30