This is very helpful. I think my false assumption was that structural contracts weren't enforced, even with protocols. Your example is very helpful.
On 30 January 2012 11:43, Timo Mihaljov <t...@mihaljov.info> wrote: > As I understand the problem in your example, you do have a definition > for what an Insurable is, but it's implicit: there's no way to check > whether an object is insurable and thus no way to check which parts of > the code break when the notion of being Insurable changes. Luckily > Clojure provides us with the tools needed to make the definition > explicit. > > In your Java example you used an interface to define what an Insurable > is. In Clojure you can do the same with a protocol: > > (defprotocol Insurable > (cost-to-replace-with-new [insurable])) > > (def insurable? (partial satisfies? Insurable)) > > Whenever you expect to receive an insurable, you can use a > precondition to make this assumption explicit, like BG and Meikel > suggested: > > (defn calculate-insurance [& insurables] > {:pre [(every? insurable? insurables)]} > ...) > > Note that the Insurable objects are completely abstract; we don't know > or care what kind of data structure are used to implement them. This > means that we can't build valid Insurables by accident, like you did > in your example by calling FuncA to FuncE, but that's a *good* thing, > because data structures built like that are very brittle, as you > noted. > > To wrap up the example, here are a two very different implementations > of Insurable. Note how everything is modeled in terms of domain > concepts instead of "maps with keys :x, :y and :z". We manipulate the > data structures with completely normal Clojure code, but keep the > knowledge of those data structures in one place only instead of > spreading it all over the codebase. This makes the code much more > robust and amenable to change. > > (defn make-simple-insurable [cost] > {:post [(insurable? %)]} > (reify Insurable > (cost-to-replace-with-new [_] > cost))) > > (defrecord CompositeInsurable [parts] > Insurable > (cost-to-replace-with-new [composite-insurable] > (->> (:parts composite-insurable) > (map cost-to-replace-with-new) > (reduce +)))) > > (defn make-composite-insurable [& parts] > {:pre [(every? insurable? parts)] > :post [(insurable? %)]} > (CompositeInsurable. parts)) > > -- > Timo > > -- > 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 > -- 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