How to avoid deeply nested switch statements?

I find the code difficult to read when I’m dealing with a bunch of Option and Result values…

1 Like

One option is to use chain which represents a monadic bind and allows you to sequence operations of the same type:

1 Like

For option types (but, unfortunately, not result) you can use do ? { … } blocks.

Yeah, the exclamation mark operator in do ? {} makes code way way more readable, but as you said it doesn’t support Result return values, which is a bummer.

I also kinda wish that after an assert Option.isSome(val) the variable val would automatically be “unwrapped” by the compiler and treated as ?val from thenceforth, kinda like what TypeScript does.

Right now, I have to do a switch statement:

switch (caseInfo) {
  case (null) { assert false };
  case (?caseInfo) {
    // do something with caseInfo
  };
};

Just this adds a nested switch layer.

The null case specifically is begging for some syntactic sugar.

Something like the following would be nice for retiring something else if you hit a null and chaining unwrapped otherwise.

myMap.get(id)?(defaultValue).myproperty;

3 Likes

Exactly I was hoping for something like that. Or even with ! instead of ?

If you assert or return anyways, you can do

let caseInfo = switch (caseInfoOpt) {
  case (null) { raise Error… };
  case (?caseInfo) { caseInfo };
};
// do something with caseInfo

It’s annoying that assert false doesn’t have a suitable return type for that, but the upcoming Debug.trap improves that.

1 Like

I’m assuming you mean throw instead of raise.

This is a neat trick, but the issue is that I can’t turn it into a private helper function because throw only works in an async context.

Interesting about Debug.trap. I see it in the docs but I guess it still hasn’t shipped with the latest version of Motoko yet? It should work since the return type is None, as you suggested.

1 Like

You could write this as

Option.get(myMap.get(id), defaultValue).myProperty
1 Like

I think it’s in the latest Motoko release, but not yet the latest dfx release.

1 Like

You can make the helper function async, and call it with await, can’t you? I think that’s the “official” solution for abstracting over code that throws or awaits.

Yeah I suppose so, although I’d like not to incur the 2-5s wait time for updates but I guess that’s what Debug.trap will be for.

A while back I sketched out a version of do notation using a function that used try/catch under the hood.

In addition to the async overhead I also ran into this limitation: Parametric polymorphism and async

1 Like