Stream: beginners

Topic: expect crash


view this post on Zulip Jonathan Kelly (Mar 02 2025 at 10:46):

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

view this post on Zulip hchac (Mar 02 2025 at 14:23):

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.

view this post on Zulip hchac (Mar 02 2025 at 14:29):

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.

view this post on Zulip Brendan Hansknecht (Mar 02 2025 at 18:31):

I'm not sure why expect a == 4.3 forces a 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.

view this post on Zulip Brendan Hansknecht (Mar 02 2025 at 18:32):

I think floats intentionally don't have equality cause equality on binary floats is almost always a mistake.

view this post on Zulip Brendan Hansknecht (Mar 02 2025 at 18:32):

https://www.roc-lang.org/builtins/Num#is_approx_eq

view this post on Zulip Brendan Hansknecht (Mar 02 2025 at 18:32):

:point_up: is the builtin solution

view this post on Zulip Jonathan Kelly (Mar 02 2025 at 18:59):

Thanks.
roc check is brilliant.
I was surprised by the whole "you can't == floats" thing, but I like it ... I think. :)

view this post on Zulip Brendan Hansknecht (Mar 02 2025 at 19:00):

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).

view this post on Zulip Brendan Hansknecht (Mar 02 2025 at 19:02):

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.

view this post on Zulip hchac (Mar 03 2025 at 02:18):

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 for F32 or F64 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