{"action":"created","issue":{"url":"https://api.github.com/repos/MangelMaxime/Thoth/issues/80","repository_url":"https://api.github.com/repos/MangelMaxime/Thoth","labels_url":"https://api.github.com/repos/MangelMaxime/Thoth/issues/80/labels{/name}","comments_url":"https://api.github.com/repos/MangelMaxime/Thoth/issues/80/comments","events_url":"https://api.github.com/repos/MangelMaxime/Thoth/issues/80/events","html_url":"https://github.com/MangelMaxime/Thoth/issues/80","id":384127541,"node_id":"MDU6SXNzdWUzODQxMjc1NDE=","number":80,"title":"[Discussion] What should be promoted as the \"right\" approach","user":{"login":"alfonsogarciacaro","id":8275461,"node_id":"MDQ6VXNlcjgyNzU0NjE=","avatar_url":"https://avatars0.githubusercontent.com/u/8275461?v=4","gravatar_id":"","url":"https://api.github.com/users/alfonsogarciacaro","html_url":"https://github.com/alfonsogarciacaro","followers_url":"https://api.github.com/users/alfonsogarciacaro/followers","following_url":"https://api.github.com/users/alfonsogarciacaro/following{/other_user}","gists_url":"https://api.github.com/users/alfonsogarciacaro/gists{/gist_id}","starred_url":"https://api.github.com/users/alfonsogarciacaro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alfonsogarciacaro/subscriptions","organizations_url":"https://api.github.com/users/alfonsogarciacaro/orgs","repos_url":"https://api.github.com/users/alfonsogarciacaro/repos","events_url":"https://api.github.com/users/alfonsogarciacaro/events{/privacy}","received_events_url":"https://api.github.com/users/alfonsogarciacaro/received_events","type":"User","site_admin":false},"labels":[{"id":743427877,"node_id":"MDU6TGFiZWw3NDM0Mjc4Nzc=","url":"https://api.github.com/repos/MangelMaxime/Thoth/labels/question","name":"question","color":"cc317c","default":true}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":7,"created_at":"2018-11-25T22:46:06Z","updated_at":"2018-11-26T18:15:01Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"Thoth.Json is primarily focused on letting you write custom coders for your type. However, when removing JSON serialization in Fable 2, we gave it some auto (de)serialization capabilities. As expected, people are using these auto (de)serializers to make the Fable 2 upgrade easier. But there're some issues with this approach:\r\n\r\n- `Decode.Auto` makes reference to most of the \"primitive\" types supported by Fable. This pulls code from Fable polyfills increasing the bundle size even if the types are not used in the app at all: datetimes, maps, decimals, bigints (specially the last two and probably also longs).\r\n- As soon as the user wants to use a custom decoder for one type, they need to write decoders for all the other types.\r\n- The map is compiled as an arrays of arrays. This is done to avoid problems when the key is not easily converted to string, but it's confusing as most users will expect them to transform to JSON objects.\r\n\r\nI'm the first one to acknowledge how difficult is to maintain a \"magic\" serialization library, and I'm super happy of removing it in Fable 2. But on the other hand, as we're promoting F# fullstack, users will expect to have an easy way to share the types between client and server without having to write so much boilerplate.\r\n\r\nPossible solutions:\r\n\r\n- Leave it more or less as is and tell users that as soon as they have specific needs they should write custom decoders for the whole domain.\r\n- Try to balance custom and auto decoders, for example, by allowing to pass a dictionary/function with custom decoders that could override the default ones.\r\n- Have a different library that focus on the auto serialization? Could make sense to promote @zaid-ajaj SimpleJson like this? (though, for what I've seen SimpleJson has similar problems to those listed above).\r\n\r\n> I'm adding a fix to reflection in Fable 2.1 to prevent code duplication when calling `typeof` several times on related types."},"comment":{"url":"https://api.github.com/repos/MangelMaxime/Thoth/issues/comments/441741426","html_url":"https://github.com/MangelMaxime/Thoth/issues/80#issuecomment-441741426","issue_url":"https://api.github.com/repos/MangelMaxime/Thoth/issues/80","id":441741426,"node_id":"MDEyOklzc3VlQ29tbWVudDQ0MTc0MTQyNg==","user":{"login":"alfonsogarciacaro","id":8275461,"node_id":"MDQ6VXNlcjgyNzU0NjE=","avatar_url":"https://avatars0.githubusercontent.com/u/8275461?v=4","gravatar_id":"","url":"https://api.github.com/users/alfonsogarciacaro","html_url":"https://github.com/alfonsogarciacaro","followers_url":"https://api.github.com/users/alfonsogarciacaro/followers","following_url":"https://api.github.com/users/alfonsogarciacaro/following{/other_user}","gists_url":"https://api.github.com/users/alfonsogarciacaro/gists{/gist_id}","starred_url":"https://api.github.com/users/alfonsogarciacaro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alfonsogarciacaro/subscriptions","organizations_url":"https://api.github.com/users/alfonsogarciacaro/orgs","repos_url":"https://api.github.com/users/alfonsogarciacaro/repos","events_url":"https://api.github.com/users/alfonsogarciacaro/events{/privacy}","received_events_url":"https://api.github.com/users/alfonsogarciacaro/received_events","type":"User","site_admin":false},"created_at":"2018-11-26T18:15:01Z","updated_at":"2018-11-26T18:15:01Z","author_association":"CONTRIBUTOR","body":"> I am not for this solution, this mean the users will need to modify a dict based on its usage of the types. Which are potentially deeply nested in his code.\r\n\r\n@MangelMaxime Consider the following example:\r\n\r\n```fsharp\r\ntype Foo =\r\n    | Foo of int\r\n    // For some reason I want to serialize Foo as int\r\n    static member Encode (x: Foo) =\r\n        let (Foo i) = x\r\n        Encode.int i\r\n\r\ntype ComplexTypeA =\r\n    { FieldA: string\r\n      // Many more fields here\r\n      FieldZ: Foo }\r\n    // I want to use Encode.Auto.generateEncoder() here (when it's available)\r\n    // but one of the fields is Foo which has a manual encoder, so I can't\r\n    static member Encode (x: ComplexTypeA) =\r\n        Encode.obj [ ... ]\r\n\r\ntype Test =\r\n    { FieldA : ComplexTypeA\r\n      FieldB : SimpleTypeB }    \r\n    static member Encoder (v : Test) =\r\n        Encode.object [\r\n            \"fieldA\", ComplexTypeA.Encoder v.FieldA\r\n            \"fieldB\", SimpleTypeB.Encoder v.FieldB\r\n        ]\r\n```\r\n\r\nJust because we want to serialize `Foo` in a particular way, we cannot use auto encoders in any type that uses it. And there are other, worser, corner cases: for example, we can add the `Foo` field to a type later on and forget to change from auto to manual encoder, or `Foo` can be in a nested type and we don't take this into account when picking an auto encoder.\r\n\r\nHowever, if we had the dictionary, we only need to remember to update it, whenever we want to have a manual encoder for some types.\r\n\r\n```fsharp\r\nlet manualEncoders = Map [\r\n    typeof<Foo>.FullName, (fun (x: Foo) ->\r\n        let (Foo i) = x\r\n        Encode.int i)\r\n]\r\n\r\n// An alternative would be to use a function instead of a dictionary\r\nlet manualEncodersFn (t: Type) (x: obj) =\r\n    if t.FullName = typeof<Foo>.FullName then\r\n        let (Foo i) = x :?> Foo\r\n        Encode.int i |> Some\r\n    else None\r\n\r\ntype ComplexTypeA =\r\n    { FieldA: string\r\n      // Many more fields here\r\n      FieldZ: Foo }\r\n    static member Encode (x: ComplexTypeA) =\r\n        Encode.Auto.generateEncoder(manualEncoders)\r\n```\r\n  "}}
{"actor":{"display_login":"alfonsogarciacaro"}}