{"action":"created","issue":{"url":"https://api.github.com/repos/ugorji/go/issues/131","repository_url":"https://api.github.com/repos/ugorji/go","labels_url":"https://api.github.com/repos/ugorji/go/issues/131/labels{/name}","comments_url":"https://api.github.com/repos/ugorji/go/issues/131/comments","events_url":"https://api.github.com/repos/ugorji/go/issues/131/events","html_url":"https://github.com/ugorji/go/issues/131","id":125241023,"number":131,"title":"Q: options for passing config/hints/modes to codec.Selfer implementations?","user":{"login":"heavenlyhash","id":627638,"avatar_url":"https://avatars.githubusercontent.com/u/627638?v=3","gravatar_id":"","url":"https://api.github.com/users/heavenlyhash","html_url":"https://github.com/heavenlyhash","followers_url":"https://api.github.com/users/heavenlyhash/followers","following_url":"https://api.github.com/users/heavenlyhash/following{/other_user}","gists_url":"https://api.github.com/users/heavenlyhash/gists{/gist_id}","starred_url":"https://api.github.com/users/heavenlyhash/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/heavenlyhash/subscriptions","organizations_url":"https://api.github.com/users/heavenlyhash/orgs","repos_url":"https://api.github.com/users/heavenlyhash/repos","events_url":"https://api.github.com/users/heavenlyhash/events{/privacy}","received_events_url":"https://api.github.com/users/heavenlyhash/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2016-01-06T19:10:19Z","updated_at":"2016-02-17T05:19:28Z","closed_at":null,"body":"#### The Situation:\r\n\r\nI have a tree of structures.  When I want to serialize all of their info, I toss them into `codec.NewEncoder([...]).Encode(theObj)`, and all is well.\r\n\r\nHowever, my application frequently wants to serialize some subset of the tree, or have something three levels deep in the tree encode itself in a different way.   It's *super* common, performance-critical levels of usage, because this is used to compute IDs of objects, as well as partial IDs that are used for indexing.  So, how can I pass configuration information to my serialization methods, so that they can do intelligent application-mode-specific things?\r\n\r\nRoughly, I'm dreaming of something perhaps resembling `codec.NewEncoder([...]).Encode(theObj, \"hint:justIDs\")` -- have that extra piece of info just handed verbatim to each step of encoding so the `CodecEncodeSelf()` method could make conditional choices in encoding if necessary.\r\n\r\n#### Options considered:\r\n\r\n- I have `CodecEncodeSelf(*Encoder)` to work with.\r\n  -  Can I attach anything to this so I can sneak my application-specific knowledge in?  I can't see any way to attach any extra info to `*Encoder` (it's a struct and has no public fields).\r\n- I could put an `encodingStyle` field inside my tree.\r\n  - Would work, but Super, super ugly.  Adding these extra bytes to the struct for all time is wasteful.  Also it would have to be on every single leaf since `CodecEncodeSelf` doesn't expose any way to, e.g. look back up to the top of the tree.  (Could put pointers back to top of tree in every relevant leaf, but that's basically the same: not good use of memory.)\r\n- Mutate my objects.  Zero out fields when encoding in a mode that should ignore them; mutate them even more complicatedly if they \r\n  - Workable.  Inefficient: at minimum, lots of memcopies just so I can zero/mutate things without corrupting originals.  (In my example use case where I'm using this to generate IDs / indexing keys, I almost always still want the unmolested object as well as the results of the serialization still in memory, so just accepting destructive mutation to avoid the memcopies is not an option.)\r\n- Use additional `type` defs liberally, one for each encoding mode needed, and attach different `CodecEncodeSelf` implementations to each.\r\n  - Not good, results in spaghetti code if doing this to a complex tree.  If there's a tree that's *mostly* homogenous between two modes, and just *one* leave that a mode three levels deep in the tree, every parent has to have type defs too.  And there's no good way to do that in golang: you can't have a type def that aliases an interface in the type it's renaming to a more specific type (even writing that sentence is a bit of a mindbender).\r\n- Use \"goroutine local storage\": https://github.com/jtolds/gls\r\n  - Ew.  This concept isn't built-in to go for a reason.\r\n\r\nLooking for feedback on any ideas I may have missed.  (This may be an esoteric use case, and if this library doesn't have or want to have explicit support for it, that'd be completely understandable.)\r\n\r\nAdding a public `Attachment interface{}` field to the `codec.Encoder` type for free use by the application would solve my problem, and seems to work okay in other libraries in other languages.  Or, adding a `Encode(obj interface{}, hint interface{})` method to `codec.Encoder` and a new interface `codec.SelferWithHint` with matching additonal param on its methods.   But I'm open to the idea there may be other mechanisms I haven't thought of that would work better."},"comment":{"url":"https://api.github.com/repos/ugorji/go/issues/comments/185029598","html_url":"https://github.com/ugorji/go/issues/131#issuecomment-185029598","issue_url":"https://api.github.com/repos/ugorji/go/issues/131","id":185029598,"user":{"login":"ugorji","id":1222082,"avatar_url":"https://avatars.githubusercontent.com/u/1222082?v=3","gravatar_id":"","url":"https://api.github.com/users/ugorji","html_url":"https://github.com/ugorji","followers_url":"https://api.github.com/users/ugorji/followers","following_url":"https://api.github.com/users/ugorji/following{/other_user}","gists_url":"https://api.github.com/users/ugorji/gists{/gist_id}","starred_url":"https://api.github.com/users/ugorji/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ugorji/subscriptions","organizations_url":"https://api.github.com/users/ugorji/orgs","repos_url":"https://api.github.com/users/ugorji/repos","events_url":"https://api.github.com/users/ugorji/events{/privacy}","received_events_url":"https://api.github.com/users/ugorji/received_events","type":"User","site_admin":false},"created_at":"2016-02-17T05:19:27Z","updated_at":"2016-02-17T05:19:27Z","body":"Sorry for long delay.\r\n\r\nI thought about this a fair amount, but couldn't come up with any solution that cleanly would fit into the framework and keep to the design philosophy and be generally useful.\r\n\r\nI wish I had some ideas to share, even if just for discussion sake. But I'm drawing a blank. And I don't think any of the ideas you espoused would meet that criteria.\r\n\r\nSorry :( "}}