My first roc program ... I was trying to work out how to do tests first, so was experimenting with "expect"
import pf.Stdout
Tuple: { x: F64, y: F64, z: F64, w: F64 }
tuple_to_string: Tuple -> Str
tuple_to_string = |{x:x, y:y, z:z, w:w}|
"{x:${Num.to_str(x)}, y:${Num.to_str(y)}, z:${Num.to_str(z)}, w:${Num.to_str(w)}}"
test_01! = |_|
_ = Stdout.line! ("Scenario: A tuple with w=1.0 is a point")
tuple = {x:4.3, y:-4.2, z:3.1, w:1.0}
{x:a,y:b,z:c,w:d} = tuple
#expect a == 4.3
#_ = Stdout.line!("a is ${Num.to_str(a)}")
Stdout.line!("tuple is ${tuple_to_string(tuple)}")
main! = |_args|
test_01!(1)
If I uncomment the expect ... I get
thread '<unnamed>' panicked at crates/compiler/mono/src/ir/pattern.rs:1044:26:
internal error: entered unreachable code: only optional destructs can be optional fields
note: run with RUST_BACKTRACE=1
environment variable to display a backtrace
Hi Jonathan,
I myself am also a beginner to Roc. One thing I've noticed is that when roc build
or roc run
show a crash like this, it's because it encountered an issue with the types, and there might be a bug somewhere at the moment that crashes the compiler with build
and run
.
However, you can run: roc check <filename>
and it'll tell you what the type issue is:
── TYPE MISMATCH in test.roc ───────────────────────────────────────────────────
This 1st argument to tuple_to_string has an unexpected type:
18│ Stdout.line!("tuple is ${tuple_to_string(tuple)}")
^^^^^
This tuple value is a:
{
w : Frac Binary64,
x : Frac Decimal,
y : Frac Binary64,
z : Frac Binary64,
}
But tuple_to_string needs its 1st argument to be:
{
w : F64,
x : F64,
y : F64,
z : F64,
}
────────────────────────────────────────────────────────────────────────────────
1 error and 3 warnings found in 29 ms.
Looks like by running expect a == 4.3
the type inferred for a, and subsequently x, is a Dec
. This clashes with what tuple_to_string
expects (all F64s).
I'm not sure why expect a == 4.3
forces a
to be a Dec (don't know how the type inference works, yet).
I tried expect a == 4.3f64
, but it looks like equality might not be implemented for f32
or f64
yet? Hopefully someone with more knowledge can chime in.
Aside from that, remember to give roc check
a shot whenever you encounter a crash like that.
If you turn the equality into a delta/error comparison though, it type checks fine:
expect Num.abs(a - 4.3) < 0.001
Replace 0.001
with your preferred level of accuracy.
I'm not sure why
expect a == 4.3
forcesa
to be a Dec (don't know how the type inference works, yet).
That is likely a type inference bug. Dec
is the default fractional type.
I think floats intentionally don't have equality cause equality on binary floats is almost always a mistake.
https://www.roc-lang.org/builtins/Num#is_approx_eq
:point_up: is the builtin solution
Thanks.
roc check is brilliant.
I was surprised by the whole "you can't == floats" thing, but I like it ... I think. :)
Oh actually, just realized it isn't a bug. By using == 4.3
, you are guaranteeing the type must be Dec
(cause F32
and F64
don't have equality).
So the main bug is that roc check
gives full nice errors, but roc build
and roc run
fail to. They also should surface all the same errors as check, but in the current compiler that is definitely not the case.
Brendan Hansknecht said:
I think floats intentionally don't have equality cause equality on binary floats is almost always a mistake.
I was reading the abilities
doc, and stumbled on this paragraph in the Builtins section:
Eq
is not derived forF32
orF64
as these types do not support structural equality. If you need to compare floating point numbers, you must provide your own function for comparison.
So that confirms it was intentional.
Last updated: Jul 06 2025 at 12:14 UTC