Is there a way to get a compile-time error when a field is added to a record type but its corresponding JSON encoder is not?

107 views
Skip to first unread message

Andres Riofrio

unread,
Apr 7, 2017, 8:48:25 AM4/7/17
to Elm Discuss
For example, I have the following code:

type alias Account =
 
{ id : Int
 
, name : String }

-- ... in another module ...

accountToJson
: Account -> Json.Encode.Value
accountToJson act
= Json.Encode.object
 
[ ("id", Json.Encode.int act.id)
 
, ("name", Json.Encode.string act.name)
 
]

If I add a field to Account, I'd like the compiler to make sure it won't be skipped in the output JSON. The way I have written the encoder, the compiler will happily let me skip the field in the serialized version of my data.

I thought about using destructuring like so:

accountToJson : Account -> Json.Encode.Value
accountToJson
{id, name} = Json.Encode.object
 
[ ("id", Json.Encode.int id)
 
, ("name", Json.Encode.string name)
 
]



But according to the documentation, this will compile fine even if Account gains a new record.

Any ideas on how to add this bit of type-safety to my application?

Peter Damoc

unread,
Apr 7, 2017, 9:04:03 AM4/7/17
to Elm Discuss
To my understanding, the only way to add that kind of safety is to implement a build plugin that analyzes your encoders. 

The encoder code is perfectly valid because you might not want to encode everything from a record so, Elm will allow you to do that just like it will allow you to name those JSON field whatever you like (even misspelled names of your record fields) 




--
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.
For more options, visit https://groups.google.com/d/optout.



--
There is NO FATE, we are the creators.
blog: http://damoc.ro/

Ian Mackenzie

unread,
Apr 7, 2017, 10:24:23 AM4/7/17
to Elm Discuss
You could change the signature instead of the definition:

accountToJson : { id : Int, name : String } -> Json.Encode.Value

accountToJson act 
= Json.Encode.object
  
[ ("id", Json.Encode.int act.id)
  
, ("name", Json.Encode.string act.name)
  
]

For example, https://ellie-app.com/RcvWmTyWFga1/0 triggers a compile error but if you remove the address field then the encoder compiles again.

Ian Mackenzie

unread,
Apr 7, 2017, 10:41:29 AM4/7/17
to Elm Discuss
Also, not a compile-time check, but one other thing I like to do is add fuzz tests that verify that my encoders and decoders are actually inverses of each other. I create fuzzers for all of my types, and have a generic jsonRoundTrips test that takes a fuzzer, an encode function and decode function. It checks that for every value produced by the fuzzer, encoding the value and then decoding succeeds and gives you back the original value. Then the compiler can tell you about any problems in your decoder (since it will force you to provide a value for each field in your record when constructing it), and the tests will tell you about any problems in your encoder (since if you forget a field when encoding, then decoding will fail). Not to mention that the test will also catch other silly errors like Encode.object [ ( "firstName", Encode.string person.firstName ), ( "lastName", Encode.string person.firstName ) ].

Daniel Bachler

unread,
Apr 7, 2017, 10:44:42 AM4/7/17
to Elm Discuss
Ian's solution is quite nice. Another way to go is that if you also have a json decoder to have an elm-test case that ensures that accountToJson >> jsonToAccount is an identity operation. For the decoder you would already get a type error and probably remember to add the new field in the encoder as well, but if you forget it the tests would have your back.

art yerkes

unread,
Apr 8, 2017, 12:05:25 PM4/8/17
to Elm Discuss
I wrote this recently:


which at least for normally sized objects will fail to compile if you're missing a field in an object.  It isn't perfect but one advantage is that you build encoder and decoder pairs together.

Andres Riofrio

unread,
Apr 8, 2017, 9:36:57 PM4/8/17
to Elm Discuss
Wow, awesome suggestions guys. I especially like Ian's fuzzing solution.

Once I'm past the prototyping phase in my project, I'll add such a fuzzer to my test suite.
Reply all
Reply to author
Forward
0 new messages