It would basically return x if the pattern matches and null if it doesn’t? Or maybe there is another way to do this. I was experimenting on the playground below and almost got there but a trap keeps me from failing well and try/catch doesn’t seem to catch it.
I’ve tried a try/catch, but that doesn’t seem to be working and I suspect I can only use that in an async function. How do you ignore recover from this in motoko?
I also tried:
I also tried
private func test((#text(val) or #nat(val2): testtype)) : Text {
return val.value;
};
But it didn’t like variables with additive patterns or something like that.
Yeah. Switch statements. But when you use these in production they get insane. I had direct criticism yesterday from a code auditor that the code was extremely hard to read due to the nested switch statements. They are very hard to manage when you want to get information back to the user and not just throw/assert.
Paul’s solution above is pretty good (I would probably use that), but to add on there are some pretty nifty helper functions in motoko-base/Option.mo at master · dfinity/motoko-base · GitHub if you’re looking just to see that a value exists and not necessarily to unwrap that value. Depending on your use case and the number of types you’re trying to narrow down, you may not even need a variant/switch statement in the first place.
Specifically, Option.get() favors a pattern that produces the value or a default, and Option.isSome() is essentially the exists() pattern.
Yep…I’ve started to use some of those in certain situations and they are great help. The Option.get is frustrating because if you any kind of complex type you have to create a “default” for it. Not a big deal, but if the type is complex things like equivalence become difficult.
I would love something like Option.get(x, return #error(“some error”), but you can’t do that because the second parameter is executed before being passed to the function.
let x = if(Foo.nat(y) != null){return Foo.nat(y);}ele {return #error("some error"};
but that is almost as hard as having to read as scrolling up to figure out what .nat does. I’m interested in trying to increase the amount of information conveyed to the reader with the fewest bits possible and about 80% of the solution is boilerplate.
If I’ve tested if something is null and reacted to it I probably want to use the unwrapped version elsewhere in my code. So I end up with this pattern everywhere:
let x :Nat = switch(x){
case(null){ return #error("x was null, try again")};
case(?x){x};
}
I’ve highlighted the cruft that conveys no information:
I’m a bit confused about the types involved in your example. What is the type of x? I imagine the problem isn’t to do with evaluation but rather with type checking.
I’m a bit confused about the types involved in your example. What is the type of x ? I imagine the problem isn’t to do with evaluation but rather with type checking.
For this one I want an early return to the user telling them that something isn’t found or configured
let found_user : User = Option.get(sate.users.get(user_id), return #err(“user not found”)); //dont do this or you will be up until three am convinced you are going crazy and your significant other will be mad at you in the morning when you fall asleep at the breakfast table
Are you trying to early return from some function scope here? Otherwise it looks like you’re trying to unify Text and { #error : Text }
Exactly! I want to return here and tell the user to get their stuff together before calling the is function again. You wouldn’t have to return #err there, you could provide a default…so it would be like Option.get but with an in context executable block that only gets executed if the bang hits.
I suspect Result Is the way to do this, but there isn’t built in syntax for that. If you have a more complete example of what you want to do with found_user I could demonstrate how to do that.
Right…but my frustration with this is that if I’m solving for x it is likely because I want to add it something or subtract it or do something. When I get there in my code I have to do another switch to get it out of the ?Nat.
@skilesare, or use another do. That is natural and intentional: hitting null is a kind of failure, and if there is the possibility of failure somewhere earlier in a code path, it has to propagate outwards. The type system does not allow you to “forget” that possibility. Null has to either be handled or propagated; do is the convenient way to propagate it, switch a way to handle it.
Ahh…interesting, so since you have the wrapped type(in a result) you use the wrapped time functions to unwrap it. These are great suggestions and I’ll incorporate them, but…well it is still …and maybe even more…hard to read and follow what is going on.
One question. access takes a type param so you can use this for a generic. In the second line of access you call chain with Ok(the generic type), but Result.Chain uses <R1, R2, Error> and It thought R1 and R2 had to be result types themselves. What is going on here that marshals your Bool into a R2?