{"action":"opened","issue":{"url":"https://api.github.com/repos/crystal-lang/crystal/issues/6309","repository_url":"https://api.github.com/repos/crystal-lang/crystal","labels_url":"https://api.github.com/repos/crystal-lang/crystal/issues/6309/labels{/name}","comments_url":"https://api.github.com/repos/crystal-lang/crystal/issues/6309/comments","events_url":"https://api.github.com/repos/crystal-lang/crystal/issues/6309/events","html_url":"https://github.com/crystal-lang/crystal/issues/6309","id":337321564,"node_id":"MDU6SXNzdWUzMzczMjE1NjQ=","number":6309,"title":"[RFC] Out of the box JSON/YAML serialization","user":{"login":"asterite","id":209371,"node_id":"MDQ6VXNlcjIwOTM3MQ==","avatar_url":"https://avatars0.githubusercontent.com/u/209371?v=4","gravatar_id":"","url":"https://api.github.com/users/asterite","html_url":"https://github.com/asterite","followers_url":"https://api.github.com/users/asterite/followers","following_url":"https://api.github.com/users/asterite/following{/other_user}","gists_url":"https://api.github.com/users/asterite/gists{/gist_id}","starred_url":"https://api.github.com/users/asterite/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/asterite/subscriptions","organizations_url":"https://api.github.com/users/asterite/orgs","repos_url":"https://api.github.com/users/asterite/repos","events_url":"https://api.github.com/users/asterite/events{/privacy}","received_events_url":"https://api.github.com/users/asterite/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-07-01T20:58:46Z","updated_at":"2018-07-01T20:58:46Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"Even though `JSON::Serializable` is a big improvement over `JSON.mapping`, having to include `JSON::Serializable` in every type feels like a burden.\r\n\r\nIn many other languages, for example, C#, Go, and I guess Java, serialization works out of the box through runtime reflection. We can do the same in Crystal, with compile-time reflection.\r\n\r\nThe way to do this is this: we define `Object.from_json(string_or_io)`, on every Object. What this does is create an instance with `allocate` (unsafe), create a `JSON::PullParser` and pass it to an instance method named `initialize_from_json`. This method is very similar to the `initialize(pull_parser)` we have. Because this method will raise if a property is not found in the JSON source for a required property (a property without a default value, and not nilable), it's totally safe.\r\n\r\nThe benefit is not having to require `JSON::Serializable` in every object that needs to be serialized. You could do:\r\n\r\n```crystal\r\nrequire \"json\"\r\n\r\nrecord Point, x : Int32, y : Int32\r\n\r\n# Works!\r\nPoint.from_json(%({\"x\": 1, \"y\": 2}))\r\n```\r\n\r\nand it will work right away. Serialization can still be controlled via attributes.\r\n\r\nTake for example https://github.com/crystal-lang/crystal/pull/6308 . It's nice, but having to manually include the `JSON::Serializable` module feels redundant, especially for records and simple types.\r\n\r\nAnother benefit is that no module is included, which means #6194 won't trigger (for this case).\r\n\r\nYet another benefit is that imagine you define some simple types in your library. If people want to serialize them, they can do it right away, no need to reopen them and include `JSON::Serializable` in case the author forgot.\r\n\r\nThe diff to achieve this is very simple, except there's a compiler bug that prevents this from working (I can work on that).\r\n\r\nI'm pretty sure many will say it might be \"dangerous\" to allow serialization on every type. I don't find it like that. And given that there's precedent in basically every other language out there, I think it's fine.\r\n\r\nThoughts?"}}
{"actor":{"display_login":"asterite"}}