I think I found a bug in the compiler

Hey :wave:, as the title says, I think I found a bug in Elm 0.19.

To understand why this baffled me, let me explain you what I did: I have finally found some time to update the codebase at Yodel from 0.18 to Elm 0.19.1 one app at a time. Some circular dependencies inside our apps and the big changes that happened in the 0.19 update blocked me until now (the first PR I started was in August 2018, but was never finished).

Ok, long story short, we have a module called ShortUUID which allows us to convert (long) UUIDs like "64d7280f-736a-4ffa-b9c0-383f43486d0b" to a shorter version ("DTEETeS5R2XxjrVTZxXoJS") back and forth. You can find it here. I converted the code to 0.19 and also switched from the unsupported hickscorp/elm-bigint to the compatible cmditch/elm-bigint. And my tests kept failing for an hour or so. I suspected the new BigInt package and wanted to call it a day. And then I found the problem:

This is the working version:

encodeHelper : String -> BigInt -> String
encodeHelper output input =
    if BigInt.gt input zero then
        let
            index =
                input
                    |> BigInt.modBy abcLength
                    |> Maybe.map BigInt.toString
                    |> Maybe.andThen String.toInt
                    |> Maybe.withDefault 0

            char =
                abc
                    |> List.getAt index
                    |> Maybe.withDefault ' '

            newInput =
                BigInt.div input abcLength

            newOutput =
                String.cons char output
        in
        encodeHelper newOutput newInput

    else
        output

and this is the broken one:

encodeHelper : String -> BigInt -> String
encodeHelper output input =
    if BigInt.gt input zero then
        let
            index =
                newInput
                    |> BigInt.modBy abcLength
                    |> Maybe.map BigInt.toString
                    |> Maybe.andThen String.toInt
                    |> Maybe.withDefault 0

            char =
                abc
                    |> List.getAt index
                    |> Maybe.withDefault ' '

            newInput =
                BigInt.div input abcLength

            newOutput =
                String.cons char output
        in
        encodeHelper newOutput newInput

    else
        output

Do you see the difference? I used newInput in the first index assignment instead of just input. And the compiler did not say a single word, which is very Elm-unlike. :wink: newInput is clearly defined below, and should in my opinion not be available above its definition.

My question now: Is this intended behavior or a bug in the Elm compiler?

But that’s not how Elm works anywhere.

1 Like

So I have to treat local definitions like global defined ones somewhere else in my module?

Yes, I seldom worry about the order, especially once it gets longer. I’m more focused on trying to put logically related things together, not the order of execution.

1 Like

Well, then I learned something new today :blush: Thx a lot, good sir!

This behavior is necessary to support mutually recursive functions

5 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.