Pattern Matching ICRC-7/37

Motoko Devs,

I’m running into a bunch of places where our meticulously engineered responses are making writing tests harder because we run into an array and pattern matching becomes complicated.

Before: #ok(#Ok(Nat))

switch(approvalResponse, approvalResponse1, approvalResponse2, approvalResponse3, approvalResponse4){
    case(#ok(#Ok(_)),#ok(#Ok(_)),#ok(#Ok(_)),#ok(#Ok(_)),#ok(#Ok(_))){};
    case(_){
       return assert(false);
    };
  };

After: we moved to batch by default and returns look like #ok([?#Ok(Nat)])

switch(approvalResponse, approvalResponse1, approvalResponse2, approvalResponse3, approvalResponse4){
    case(#ok(val1),#ok(val2),#ok(val3),#ok(val4),#ok(val5)){
      switch(val1[0], val2[0], val3[0], val4[0], val5[0]){
        case(?#Ok(_), ?#Ok(_), ?#Ok(_), ?#Ok(_), ?#Ok(_)){

        };
         case(_){
          return assert(false);
        };
      };
    };
    case(_){
       return assert(false);
    };
  };

Is there a clever way to pattern match inside an array? I’m fine with a trap here since it is a test.

If not, can we get one? Something like:

switch(approvalResponse, approvalResponse1, approvalResponse2, approvalResponse3, approvalResponse4){
    case(#ok([[0]?val; [1]?val2])){};
    case(_){
       return assert(false);
    };
  };

You can of course pattern-match an array, but only for a fixed length. For example, if all arrays are expected to have a single element, then this works:

case (#ok([?#Ok(_)]), #ok([?#Ok(_)]), #ok([?#Ok(_)]), #ok([?#Ok(_)]), #ok([?#Ok(_)])) { ... }

Or for 2:

case (#ok([?#Ok(_), _]), #ok([?#Ok(_), _]), #ok([?#Ok(_), _]), #ok([?#Ok(_), _]), #ok([?#Ok(_), _])) { ... }

etc., but Motoko does not have ellipses for matching “the rest” of an array of arbitrary size.

That said, I’d not overuse nested patterns, since that does not necessarily result in the most readable code.

1 Like

Ok…awesome! This is helpful.

It seems to not compile: