Comment made by: amalloy
Stuart: The two foo forms you give are entirely separate, and to unify the two behaviors you would have to group them together. It's not at all unreasonable to suppose the user wants to define foo once, fiddle with it, and then redefine it - clojure.core does similar stuff with let, reduce, etc.
As written, deftype/reify have a somewhat similar "look" - because there is nothing physically grouping the declaration of Map with its functions, it's not clear what should happen when a heading like Map is given twice, and it's not specified in the docs.
I think the difference is that in the reify case, the two are in the same top-level form, so the compiler can detect that you're trying to do something "weird", so a silent redefinition (reasonable for your defn example) is surprising. There are a number of solutions that would reduce this surprise:
1) Permit or require reify to group things, as in (reify (Comparable (compare (link: this other) 1))). Then the explicit grouping of Comparable with its methods serves two purposes: it implies that other definitions for Comparable should be included in that grouping; and it makes it easier to do that, because you can just iterate over forms until you find Comparable, and then insert another definition.
2) Throw an exception if an interface is specified twice. This is not ideal because it can be a lot of work for the user to group things together themselves, while it's easy for deftype to do given the grouping it's already doing. However, it would avoid the confusion and surprise, by saying "that's not allowed" rather than leaving the user guessing what's gone wrong.
3) Interpret my original example code as an attempt to open the Map interface, add implementations, and then later add some more implementations.
I would have liked reify to implement (1) to begin with, but at this point I don't think the syntax is backwards-compatible, so it doesn't seem like a good idea. I suppose either (2) or (3) is fine, and they both seem like an improvement over the current confusing behavior. Of course, I prefer (3), but I can understand a desire to make reify reject syntax that is not immediately obvious in intent rather than interpreting it as what I think is the most useful intent.