Last time I discussed using a hash maps to improve code reuse with protocols. While we produced a set of good solutions, I couldn't help but feel like we aren't quite there. There still is a fair amount of chatter on the list about how to implement a default protocol, for example.
I started experimenting with an idea I'm calling a Partially Implemented Protocol (PIP). The idea is that you can use a PIP like you would a BaseClass in Java. After playing around for a little bit, I settled on the following solution:
The two major components is the PIP record and extend+ macro. Let me re-write yesterday's example with the new expand+ syntax.
(defprotocol UIProtocol
 (render [])
 (action [evt])
 (button-down [evt])
 (button-up [evt]))
(def BaseUIProtocol
 (pip UIProtocol
 {:action (fn [this evt] ...)
   :button-down (fn ([this evt]...)
   :button-up (fn ([this evt]...)})
(extend+ TerranUIType
  BaseUIProtocol
  {:render an-existing-fn})
(extend+ ProtossUIType
  BaseUIProtocol
  {:render a-different-fn})
What I really like about the use of a PIP is that it allows reference to the protocol & partial implementation with one record. You can get at the internal simply by using keyword lookup, and you can also derive a PIP from another PIP like so:
(def up-down-override
  :button-down button-down-2
  :button-up button-up-2})
(extend+ ZergUIType
  (pip BaseUIProtocol up-down-override)
  {:render a-buggy-fn})
I'm also working on versions of reify+ proxy+, etc. that all work with PIPs, assuming this idea is worth exploring.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment