{"action":"created","issue":{"url":"https://api.github.com/repos/non/jawn/issues/32","labels_url":"https://api.github.com/repos/non/jawn/issues/32/labels{/name}","comments_url":"https://api.github.com/repos/non/jawn/issues/32/comments","events_url":"https://api.github.com/repos/non/jawn/issues/32/events","html_url":"https://github.com/non/jawn/issues/32","id":81312896,"number":32,"title":"Make JObject and JArray immutable","user":{"login":"non","id":218045,"avatar_url":"https://avatars.githubusercontent.com/u/218045?v=3","gravatar_id":"","url":"https://api.github.com/users/non","html_url":"https://github.com/non","followers_url":"https://api.github.com/users/non/followers","following_url":"https://api.github.com/users/non/following{/other_user}","gists_url":"https://api.github.com/users/non/gists{/gist_id}","starred_url":"https://api.github.com/users/non/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/non/subscriptions","organizations_url":"https://api.github.com/users/non/orgs","repos_url":"https://api.github.com/users/non/repos","events_url":"https://api.github.com/users/non/events{/privacy}","received_events_url":"https://api.github.com/users/non/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/non/jawn/labels/enhancement","name":"enhancement","color":"84b6eb"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":6,"created_at":"2015-05-27T06:57:17Z","updated_at":"2015-06-05T04:40:44Z","closed_at":null,"body":"Currently (and historically) `JObject` and `JArray` are mutable. They are case classes wrapping mutable data structures.\r\n\r\n@ijuma wisely points out that this is maybe not the best for folks who want to use long-lived `JObject` instances, and suggests it would be nice to make the types safer.\r\n\r\nHere are some possible scenarios (from least to most safe):\r\n\r\n(I) Types are constructed with mutable collections, and expose them via getters. This is the status quo.\r\n\r\n(II) Types are still constructed with mutable collections, but don't expose them directly. Data is accessed via read-only methods, or by copying the underlying data into a new structure. Mostly safe, although a fiendish user could construct a `JObject`, hang onto the mutable map, and change it later. (The parser is guaranteed not to do this.) The downside here is that it becomes more expensive to use `JObject` and `JArray` as a scratchpad during parse/modify/save cycles. (This is probably not a big deal.)\r\n\r\n(III) Provide a public constructor using an immutable map, and a private constructor used internally that uses mutable maps. This way, users can't play games with mutable data, and (assuming the parser doesn't do anything fishy) we are totally safe. The downside here is that the objects become more expensive to construct, or that we have to add different `JObject` types for the different backing structures.\r\n\r\n(IV) Convert Jawn to use immutable data structures only, possibly using builders in the Parser. This solves the safety issues, but probably increases the memory footprint and might have other performance issues.\r\n\r\nPersonally I think I prefer (II), but I'm open to hearing other suggestions."},"comment":{"url":"https://api.github.com/repos/non/jawn/issues/comments/109158950","html_url":"https://github.com/non/jawn/issues/32#issuecomment-109158950","issue_url":"https://api.github.com/repos/non/jawn/issues/32","id":109158950,"user":{"login":"non","id":218045,"avatar_url":"https://avatars.githubusercontent.com/u/218045?v=3","gravatar_id":"","url":"https://api.github.com/users/non","html_url":"https://github.com/non","followers_url":"https://api.github.com/users/non/followers","following_url":"https://api.github.com/users/non/following{/other_user}","gists_url":"https://api.github.com/users/non/gists{/gist_id}","starred_url":"https://api.github.com/users/non/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/non/subscriptions","organizations_url":"https://api.github.com/users/non/orgs","repos_url":"https://api.github.com/users/non/repos","events_url":"https://api.github.com/users/non/events{/privacy}","received_events_url":"https://api.github.com/users/non/received_events","type":"User","site_admin":false},"created_at":"2015-06-05T04:40:44Z","updated_at":"2015-06-05T04:40:44Z","body":"So, after a bit of thought, I think I will add the following methods to `JValue`:\r\n\r\n```scala\r\n// for numbers\r\ndef asInt: Int\r\n\r\n// for objects and arrays\r\ndef size: Int\r\ndef isEmpty: Boolean\r\ndef nonEmpty: Boolean\r\n\r\n// for arrays\r\ndef elements: Iterator[JValue]\r\ndef asVector: Vector[JValue]\r\n\r\n// for objects\r\ndef items: Iterator[(String, JValue)] = Iterator.empty\r\ndef asMap: Map[String, JValue]\r\n```\r\n\r\nHow does this sound @ijuma?"}}