{"action":"created","issue":{"url":"https://api.github.com/repos/bos/aeson/issues/376","repository_url":"https://api.github.com/repos/bos/aeson","labels_url":"https://api.github.com/repos/bos/aeson/issues/376/labels{/name}","comments_url":"https://api.github.com/repos/bos/aeson/issues/376/comments","events_url":"https://api.github.com/repos/bos/aeson/issues/376/events","html_url":"https://github.com/bos/aeson/issues/376","id":142114408,"number":376,"title":"Instance for Maybe loses information","user":{"login":"cgibbard","id":7033452,"avatar_url":"https://avatars.githubusercontent.com/u/7033452?v=3","gravatar_id":"","url":"https://api.github.com/users/cgibbard","html_url":"https://github.com/cgibbard","followers_url":"https://api.github.com/users/cgibbard/followers","following_url":"https://api.github.com/users/cgibbard/following{/other_user}","gists_url":"https://api.github.com/users/cgibbard/gists{/gist_id}","starred_url":"https://api.github.com/users/cgibbard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cgibbard/subscriptions","organizations_url":"https://api.github.com/users/cgibbard/orgs","repos_url":"https://api.github.com/users/cgibbard/repos","events_url":"https://api.github.com/users/cgibbard/events{/privacy}","received_events_url":"https://api.github.com/users/cgibbard/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/bos/aeson/labels/breaking%20change","name":"breaking change","color":"fbca04"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2016-03-20T00:22:38Z","updated_at":"2016-03-21T20:37:38Z","closed_at":null,"body":"```\r\nPrelude Data.Aeson> encode (Just Nothing :: Maybe (Maybe Integer))\r\n\"null\"\r\nPrelude Data.Aeson> encode (Nothing :: Maybe (Maybe Integer))\r\n\"null\"\r\n```\r\n\r\nThis just cost me way more time than I'd care to admit. Personally, I think it'd be worth fixing it by using an instance similar to the one used for Either or other sum types. Just letting TH generate the instance would be fine I think. You might want to do a major version increment to prepare people for the fact that the representation is different, but I think it's important not to have default ToJSON/FromJSON instances losing information like this."},"comment":{"url":"https://api.github.com/repos/bos/aeson/issues/comments/199467759","html_url":"https://github.com/bos/aeson/issues/376#issuecomment-199467759","issue_url":"https://api.github.com/repos/bos/aeson/issues/376","id":199467759,"user":{"login":"mgsloan","id":22570,"avatar_url":"https://avatars.githubusercontent.com/u/22570?v=3","gravatar_id":"","url":"https://api.github.com/users/mgsloan","html_url":"https://github.com/mgsloan","followers_url":"https://api.github.com/users/mgsloan/followers","following_url":"https://api.github.com/users/mgsloan/following{/other_user}","gists_url":"https://api.github.com/users/mgsloan/gists{/gist_id}","starred_url":"https://api.github.com/users/mgsloan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mgsloan/subscriptions","organizations_url":"https://api.github.com/users/mgsloan/orgs","repos_url":"https://api.github.com/users/mgsloan/repos","events_url":"https://api.github.com/users/mgsloan/events{/privacy}","received_events_url":"https://api.github.com/users/mgsloan/received_events","type":"User","site_admin":false},"created_at":"2016-03-21T20:37:38Z","updated_at":"2016-03-21T20:37:38Z","body":"It is possible to write an instance for `Maybe` which ensures its argument is not `Maybe`: https://github.com/ghcjs/ghcjs-base/pull/34/commits/6bf43075849fdd551f04a5b9d8a36e4d769e6fc2#diff-e09b67a14d374b52d6408c4ebcb9b630R7 .  There, I'm using closed type families, but I've just realized this is better:\r\n\r\n```haskell\r\nclass FromJSON a where\r\n    type FromJSONUsesNull = 'False\r\n    ...\r\n\r\nclass ToJSON a where\r\n    type ToJSONUsesNull = 'False\r\n    ...\r\n```\r\n\r\nUnfortunately, type family defaults aren't usable unless they are associated, so both are needed.  If we want to avoid `DataKinds` (dunno why that would be), we can instead use `ConstraintKinds` and instead have `ToJSONDoesn'tUseNull :: * -> Constraint`.  If it does use null, it'd yield an unsatisfiable constraint like `Error` from the singletons package.\r\n\r\nSo, it may be possible to keep the behavior but statically ensure that.  Yes, this could cause compilation errors, but they could reflect actual potential errors."}}