Debugging json decoders

887 views
Skip to first unread message

Jacob Matthews

unread,
Nov 3, 2015, 5:16:53 PM11/3/15
to elm-d...@googlegroups.com

I've been playing with Elm recently. I really like it in general, but I have had some pretty frustrating experiences debugging Json.Decode.Decoder failures, especially while handling browser events using Html.Events.on.

For instance, suppose we want to write a decoder that reads the selected index within a <select> element. We might write:

import Json.Decode exposing (..)

...

decodeSelectedIndex : Decoder string
decodeSelectedIndex = at ["action", "selectedIndex"] string  -- oops! selectedIndex is an int!

renderSelect : Html
renderSelect = 
  select 
    [ on "change" decodeSelectedIndex someHandler ]
    [ ... ]
  
The problem here is that the decoder doesn't match the value being parsed, but we can't figure out any way to either observe the raw value pre-decoding (using Debug.watch, Debug.log or even a javascript breakpoint) or to convince Html.Events.on to report an error if parsing fails -- the handler just doesn't fires, with no indication of why.

I tried creating a monitoring function 

monitorDecoder : Decoder a -> Decoder a
monitorDecoder decoder = 
  customDecoder Json.Decode.value <| \value -> decodeValue decoder (Debug.watch "decoding value" value)

so that I could write 

   on "change" (monitorDecoder decodeSelectedIndex) someHandler

but that approach always fails to decode before the watch gets evaluated -- I'm not sure why, but I suspect it's because the decoder is being asked to decode a JavaScript event, which is not JSON-serializable, and thus the Json.Decode.value decoder fails before the custom decoding logic runs at all.

Are there other strategies I can try? What do people normally do to write solid decoders? I really like Elm in general but I'm worried about not having an effective way to debug these kinds of issues.

Thanks,
-jacob

Max Goldstein

unread,
Nov 3, 2015, 5:41:31 PM11/3/15
to Elm Discuss
Running a Decoder produces a Result. Have you looked at the Err value? It should contain a string telling you exactly what went wrong.

But as for decoding JS events, have you seen this library?

Sorry if I'm missing the point of your post.

Jacob Matthews

unread,
Nov 3, 2015, 6:06:12 PM11/3/15
to elm-d...@googlegroups.com
Hi Max --

Thanks for your suggestion. We use the Err result when we can, which works for parsing the results of HTTP calls. But when using Html.Events.on we don't get the opportunity to inspect the Err value -- Html.Events.on runs the decoder directly and discards the Err value before we get a chance to inspect it. (We traced it down to https://github.com/evancz/virtual-dom/blob/master/src/Native/VirtualDom.js line 1397 -- the "if" on that line has no corresponding "else" to handle the error case, so errors silently disappear.)

I hadn't seen the elm-html-events library -- thanks! It would not have solved our particular problem, since it doesn't have anything for the events fired by manipulating <select>, but it looks very useful for avoiding these problems in the future.

I think my larger question on this front is: In most languages I use, I have some effective way to watch values flow through the system to debug problems like this. In elm, and specifically with decoders, I don't know of a way to do that, and (especially combined with an error-swallowing consumer) that makes it very hard for me to debug some of the programs I need to write. Am I missing anything here? Are there tricks that make this sort of thing easier to deal with that I don't know of?

-jacob


-jacob

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Raoul Duke

unread,
Nov 3, 2015, 6:08:44 PM11/3/15
to elm-discuss
> the "if" on that line has no corresponding "else" to handle the error case, so errors silently disappear.)

and you wonder why some languages REQUIRE an else clause.

(not that that can't be irgnored/worked around/subverted, itself, of course. :-)

Sergey Zubtsovskiy

unread,
Aug 19, 2016, 1:17:45 PM8/19/16
to Elm Discuss
Hey Jacob,

Any update on this topic? I am facing the same issue, even in Elm 0.17 with latest libraries...

OvermindDL1

unread,
Aug 19, 2016, 1:56:05 PM8/19/16
to Elm Discuss
On Friday, August 19, 2016 at 11:17:45 AM UTC-6, Sergey Zubtsovskiy wrote:
Hey Jacob,

Any update on this topic? I am facing the same issue, even in Elm 0.17 with latest libraries...

You can setup multiple branches in a decode so it one fails then you can fall back to a default value so it still passes.  You could even return a Maybe and return a default value of Nothing if you want, wrapping the main decode branch in a Just.

Simon

unread,
Aug 19, 2016, 3:31:35 PM8/19/16
to Elm Discuss

<shamless-plug>
My emulator may help - http://simonh1000.github.io/decoder/
</shamless-plug>

Sergey Zubtsovskiy

unread,
Aug 19, 2016, 4:45:32 PM8/19/16
to elm-d...@googlegroups.com
I am not sure I understand the answer. If you are talking about calling decode function then, as Jacob mentioned, it works in all cases but the one we're wondering about. 

Check this example:

onScroll tagger =
  on "scroll" (Json.Decode.map tagger decodeScrollPosition)

Where decodeScrollPosition is:
decodeScrollPosition : Json.Decode.Decoder Int

"on" function is only accepting value of type Json.Decode.Decoder. If I was decoding myself (e.g. by calling Json.Decode.decodeString) I would get a Result and process it the way you mention. But in case of an event listener decoding is happening somewhere within Elm runtime which silently swallows error. If I, for example, misspell event's field name, nothing will happen. No runtime error (that's still valid), but no result either.

I am wondering if I am missing something. To my mind it does not fit to the whole impression Elm's trying to create. And I am a bit confused.

Sergey Zubtsovskiy
sergey.zu...@gmail.com
Skype: szubtsovskiy


--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.

OvermindDL1

unread,
Aug 19, 2016, 5:06:44 PM8/19/16
to Elm Discuss
Given this:
```elm
onScroll tagger =
  on "scroll" (Json.Decode.map tagger decodeScrollPosition)
```
If you *always* want it to be called, and since we know in this case that the scroll javascript event will not return a negative number then you could do this for decodeScrollPosition:
```elm
decodeScrollPosition =
  Json.Decode.oneOf
    , Json.Decoder.succeed -1
    ]
```

Or you could parse out a `Maybe Int`, or you could parse out a structure if you want a more stuff.  Etc...  :-)

To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.

Sergey Zubtsovskiy

unread,
Aug 20, 2016, 12:10:30 PM8/20/16
to elm-d...@googlegroups.com
Thank you for explanation! I should give it a try.

Sergey Zubtsovskiy
sergey.zu...@gmail.com
Skype: szubtsovskiy


To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.

Chris Baker

unread,
Nov 3, 2016, 2:30:32 PM11/3/16
to Elm Discuss, sergey.zu...@gmail.com
I know I'm kind of late to the party here, but I was having this same problem, so I wrote some code to log the error message:

traceDecoder : String -> JD.Decoder msg -> JD.Decoder msg
traceDecoder message decoder =
    JD.value `JD.andThen` \value ->
        case JD.decodeValue decoder value of
            Ok decoded ->
                JD.succeed decoded
            Err err ->
                JD.fail <| Debug.log message <| err

Then you wrap your decoder in the trace function, e.g.

on "mousedown" (traceDecoder myDecoder)

Worked well for me.

HTH,

Chris Baker
Reply all
Reply to author
Forward
0 new messages