Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support inheritance-based fallback for write-handlers #12

Closed
greglook opened this issue Jan 31, 2019 · 5 comments
Closed

Support inheritance-based fallback for write-handlers #12

greglook opened this issue Jan 31, 2019 · 5 comments

Comments

@greglook
Copy link
Owner

There are a few real-world use-cases that have cropped up where the majority of a type's API uses an abstract parent class or interface, with multiple underlying concrete implementations. One example is Joda's org.joda.time.DateTimeZone and the attendant CachedDateTimeZone, FixedDateTimeZone, and DateTimeZoneBuilder$PrecalculatedZone (yuck). The user wants to be able to treat all of these types uniformly, so having to declare every possible subclass makes type extension awkward here.

This can be solved by attempting inheritance-based resolution, similar to puget.dispatch/inheritance-lookup.

@usernolan
Copy link

I'm running into this scenario, and think this feature would be great. Another place I've seen something similar is in transit. If I have time I will look further into how something like this would fit into clj-cbor and put together a PR.

In any case, thanks for the work you've put into this lib, it's a breeze to work with.

@greglook
Copy link
Owner Author

Thanks! Always great to hear positive feedback.

I looked into this a bit more, and there are ways to add this functionality with the existing code. In write-handled, the codec uses the :dispatch function to generate a lookup value, then calls :write-handlers as a function on that lookup to find if there is a custom handler:

(let [dispatch (:dispatch codec)
write-handlers (:write-handlers codec)]
(when-let [formatter (write-handlers (dispatch x))]

That means that a caller could either use a custom dispatch function which maps known problem classes to the desired lookup value, or they could replace the default hash-map for write-handlers with something that does more sophisticated lookup behavior.

@usernolan
Copy link

That looks great—it's cool that the library supports this without further modification.

Just to make sure I'm interpreting this correctly, are you thinking that the custom dispatch function would be convenient for manually specifying how a class should be mapped to a handler, while replacing write-handlers with something more sophisticated would capture more generic changes to the lookup algorithm?

I think I'm getting it, and if so, that solves the whole problem really cleanly. Thanks for pointing this out, this was mega helpful.

@greglook
Copy link
Owner Author

Yeah - the dispatch function would let you alias specific types if you wanted to. To use the DateTimeZone example, you could do this to address it:

(defn encoder-class
  [x]
  (if (instance? DateTimeZone x)
    DateTimeZone
    (class x)))

(def codec
  (cbor/cbor-codec :dispatch encoder-class))

You could also address it more generally by replacing the write handlers, similar to how Puget does it.

@greglook
Copy link
Owner Author

Added a utility function for this and released it in 1.0.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants