The following snippet:
app [main] {
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
}
exampleU8 : U8
exampleU8 = Num.powInt 256 0
main = crash ""
gives this error while building:
This powInt call produces:
I16, U16, F32, I32, U32, F64, I64, U64, I128, Dec, or U128
But the type annotation on exampleU8 says it should be:
U8
I can get around the error by replacing exampleU8 = Num.powInt 256 0
with exampleU8 = Num.toU8 (Num.powInt 256 0)
but I am wondering why the first form is not allowed.
FYI this is a reduction from a bigger program that was crashing while building, giving the error ambient lambda set function import is not a function, found: Error
.
Hi John,
U8 only goes to 255, so we start we something that's not a U8 which is why we end up with something that can't be U8. Because the signature of powInt
is Int a, Int a -> Int a
you need to use the same type in every "spot". The compiler does not do automatic downcasting (for good reasons probably).
hmm this is kind of subtle. it's not obvious that the value of a literal is influencing type inference in this way
It does work with
exampleU8 : U8
exampleU8 = Num.powInt 255 0
This issue came up in an old codebase that I was updating to accommodate the new changes to the language. So this has worked in the past.
To give more context, I am converting bytes (List U8) to integers.
So, when previously I was doing
resultU8 : U8
resultU8 = byte1 * (Num.powInt 256 0)
resultU16 : U16
resultU16 = byte1 * (Num.powInt 256 1) + byte2 * (Num.powInt 256 0)
now I need to do
resultU8 : U8
resultU8 = byte1 * Num.toU8 (Num.powInt 256 0)
resultU16 : U16
resultU16 = Num.toU16 byte1 * (Num.powInt 256 1) + Num.toU16 byte2 * (Num.powInt 256 0)
(byte1
and byte2
are of type U8
)
The new version is more verbose but arguably more correct as there are no hidden upcasts/downcasts.
I think really you should be using bitshifts here
and really really we should have "turn bytes into little/big/native endian number of a wider type" functions in the standard library
In an even earlier version of the code I was using Num.bytesToUxx
but they went away a couple of months ago
@Richard Feldman what's our plan here?
I think the last discussion about this left it at: this is easy enough to do in userland/a library with bit shifts. So no need to do it in the standard.
I think an annoyance with doing it in the standard is that you don't want to return a list (unnecessary allocation).
Instead, you are stuck with N different functions that return different size tuples.
Since that didn't seem like a great API, I think it was left for a user to just do the bitshifting.
Last updated: Jul 06 2025 at 12:14 UTC