Motoko's type system & converting between types

Every now and then I struggle with converting between different types Motoko has to offer.

Generally conversion within differently-sized instances of one type work well - say I want to convert an Int8 to an Int16 then there’s methods for that - might have to go via Int, but it works and behaves as expected, trapping on overflow etc.

However once you start going between different types, it quickly gets hairy. Say I want to convert a Nat to an Int. Obviously NatN might overflow an IntN, so I’d fully expect to have to handle overflow. However - as far as I can tell there is simply no way to do that at all.

I like to use Nat when a value is guaranteed to be positive, to be more semantically precise. However this then prevents me from ever using this value in a calculation where I might get a negative result.

The same goes for eg these conversions:

  • IntNNatN, this is safe so really should be easy. Yet IntN.abs() returns an… IntN. You can achieve this with a roundtrip through Int (NatN.fromNat(IntN.toInt().abs())) but let’s be real, that’s insane. :wink:
  • NatFloat. While you can convert between Int64 and Float, the inability to get anywhere from a Nat prevents this
  • Text → Numeric. Usually languages offer a way to parse a text-based representation of a numerical value - think Go’s strconv module, C’s stroto... functions etc. As far as I am able to tell, there is no such thing in Motoko.

Am I missing information? The above is based on what I could find in the docs of the stdlib, but I might have missed it. Or am I misusing the type system? Or are these simply examples of Motoko being a very young language, still?

I must say that I enjoy many of the concepts I have encountered in Motoko - pattern matching makes for much nicer error handling than magic return values or exceptions. But its type system tends to be a hindrance as often as it is a help.

3 Likes

Funny that you are asking about this now, I am currently working on numericals types. See Remove Word type by nomeata · Pull Request #214 · dfinity/motoko-base · GitHub for the motoko-base exposition of that.

As for the (wrapping) conversions between NatN and IntN: These are supported by the compiler, but so far not exposed in the base library; this will be fixed with my changes to the compiler and the above PR to base (although it could be fixed in base already now).

As for NatFloat, you can use Float.fromInt – remember that due to subtyping, you can always use a Nat where an Int is expected.

For parsing text to numbers, we don’t have that at the moment. Surely something that we might want eventually, although maybe less pressing than initially perceived: In the typical architecture where the Motoko canister implements the backend of a service, tha a frontend (e.g. in JS) communicates via strongly typed candid value, you hopefully don’t have to do much parsing in the backend – Candid supports transmitting float values as is (float64).

2 Likes

remember that due to subtyping, you can always use a Nat where an Int is expected.

Oh, that I did not consider - should have just tried it. That is helpful. :smiley:

I am currently working on numericals types

Glad to hear that, looking forward to the changes then.

For parsing text to numbers, we don’t have that at the moment. Surely something that we might want eventually, although maybe less pressing than initially perceived

Fair point, as data currently comes into canisters solely via Candid-capable interfaces, one can probably use proper numerical types in many cases.
I can however envision a few cases where I might end up with user-provided textual inputs containing numerical values. For an academic example, consider the textbook exercise of implementing a calculator.

But I can see how it might not be the most pressing matter. :slight_smile:

Appreciate the quick feedback.