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 <m...@kotka.de> 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 clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to