I'd like to discuss this design approach. (It's unrelated to the testing issue.) I avoided this design because the undo-fn is determined at do-patch! time. The use case is for a persistent system like Git where patches may be undone long after being done - e.g. long after the patch is written to the database. In the meantime, the system may be upgraded and the undo-fn for a patch may change. If the undo-fn and args is written to the database at do-patch! time, for backwards compatibility, at undo-patch! time, the undo-fn would have to be updated to whatever the new call is.
Contrast that with my current approach where only the fn is saved and the undo-fn is determined at undo-patch! time. For backwards compatibility, the undo-fn would have to support legacy fn formats, which I conjecture are slightly less likely to change than the corresponding undo-fn. This is a pure guess and is not based on real requirements yet; I don't know that fns themselves are necessarily more stable than their counterpart undo-fns. It's a vague sense that undo-fns are more subject to bug fixes: fns themselves are processed right away at do-patch! time, while undo-fns are like time bombs that lay dormant until a patch has to be undone, long after the initial patch. In addition, in the current implementation I outlined, the undone patch disappears. The real implementation will most likely be a patch with undo-patch! as the :fn and the patch being undone as the :arg. This is necessary to support merging with remote branches like in Git. undo-patch!'s may themselves be undone, which would require 2 degrees of backwards compatibility: converting the undo-fn in the first undo, and converting the fn in the second undo. Both approaches have the same 2 degrees of backwards compatibility, but the command approach still somehow seems more fragile. I'd love to get your thoughts on this. Anyone with experience working on a similar system? Thanks! Alyssa On Dec 22, 4:35 am, Meikel Brandmeyer <[email protected]> wrote: > Hi, > > maybe a different approach could be to use a richer datatype than a function, > which carries both: the command and the undo command. > > (deftype Command [action undo]) > > Then you could do something like: > > (defn do-patch! > [command args] > (dosync > (let [patch {:command command :args (vec args)}] > (apply (.action command) args) > (alter patches- conj patch) > patch))) > > (defn undo-patch! > [] > (dosync > ((.undo (:command patch))) > (alter patches- pop))) > > Then you could provide specially crafted Commands and there would not be the > need to stub anything. Also Commands wouldn't have to be global objects. > > Sincerely > Meikel -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to [email protected] Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/clojure?hl=en
