json icon indicating copy to clipboard operation
json copied to clipboard

Using `==` on `Json.Decode.Value`s can throw runtime exceptions

Open lydell opened this issue 3 years ago • 1 comments

SSCCE

elm repl
> import Json.Decode as JD
> import Json.Encode as JE
> JD.decodeString (JD.index -1 JD.value) "[]" |> Result.map (\v -> JE.object [("a", JE.null)] == v)
TypeError: Cannot read property 'a' of undefined
> JE.list identity [ JE.object [ ("a", JE.null) ] ] == JE.list JE.int []
TypeError: Cannot read property 'a' of undefined
> JE.object [ ("a", JE.object [ ( "a", JE.null ) ] ) ] == JE.object []
TypeError: Cannot read property 'a' of undefined
> JE.object [ ("$", JE.string "Set_elm_builtin" ) ] == JE.object [ ("$", JE.string "Set_elm_builtin" ) ]
TypeError: Cannot read property '$' of undefined

The above examples fail because the value on the right side of == is undefined.

Here’s an Ellie by @mpizenberg: https://ellie-app.com/cLXHgSHm8yTa1

Notes

The problem seems to be that _Utils_eqHelp assumes both its arguments are of the same type/shape. In general that’s true in Elm, but not for Json.Decode.Value. It’s a wrapper around any value, which might not be the same on both sides.

Edit: This Discourse post by Evan explains that (==) shouldn’t be used with JSON values from elm/json and an idea for improving this in the future: https://discourse.elm-lang.org/t/function-equality/7538/24

Edit 2: Apparently this is even documented! 🤦 https://package.elm-lang.org/packages/elm/core/latest/Basics#equality Though these crash for a different reason (“the implementation is not at all made for Json.Decode.Value”) than mentioned in those docs.

lydell avatar Mar 30 '21 19:03 lydell

Just ran into this as well. Here's another simple test case:

> json1 = "{ \"a\": [{}] }" |> Json.Decode.decodeString Json.Decode.value
> json2 = "{}" |> Json.Decode.decodeString Json.Decode.value
> json1 == json2
TypeError: Cannot read property '0' of undefined

My temporary solution has been to use lattyware/elm-json-diff for Json.Value equality, by checking if there's any diff between the two JSON values.

tayjohno avatar May 16 '21 14:05 tayjohno