First of all, Clojure, core.async, spec, the whole of what you guys produce is fabulous. I have nothing but respect for the work you're all doing. It's Clojure's simple design that has me enjoying programming more than ever.
That said, I'd like to add a new perspective to the discussion Mark started. It has a wider application than spec alone. Baldridge in Core Async in Use <https://www.youtube.com/watch?v=096pIlA3GDo> (great talk!) exemplifies how to do apis that are asynchronous. He encourages developers to avoid asynchronous code, pushing its necessary appearance to as few strategic points as possible. This parallels the fundamental Clojure separation of identity from state. It is by the nature of pushing the necessary manipulation of state to as few strategic points as possible that we can lean on pure functions. Using globals reduces this separation and makes a design more imperative. The possibility of fine-grained control is lost when state is pushed into globals. I can appreciate that globals have a place in simplifying a public api, but why not fully expose the underlying data structures? This was done with hierarchies. Hierarchies (the defining of is-a relationships via `derive`) are directly related to spec as evidenced by the existence of `multi-spec`. So if hiearchies, which have their own global counterpart, are exposed, it would appear consistent to expose the registry. Both are related. They're both used to define ontologies. So while spec's use of a global registry suits most cases, it complicates things for those like me who want first-class schemas. I am building a CMS where schemas are a core feature. I need to manage their lifetimes and scopes at runtime. I can't imagine it would have been much harder to implement spec using what what Gary Bernhardt refers to as a Functional Core, Imperative Shell <https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell>. It's a good principle. I find that it aligns closely with idea of deferring the messy parts for later found in both Baldridge's talk and Clojure's state management strategy. I've found that designing around a functional core increases possibilities. It's what: - makes implementing undo/redo mostly trivial. - allows control over the lifetime and scope of constructs. - enables the use of single state atoms that host nested data structures When we only have access to the imperative shell, these things are not possible. To help illustrate, the following lines are listed in the order of increasing possibility. (derive tag parent) (derive h tag parent) (swap! h (derive tag parent)) Only one of these options -- the one using a pure function -- accommodates all of the above possibilities. The longer I've done Clojure, the closer I've come to a consistent use of this approach. spec's design unnecessarily takes things off the table. I know I'm being dogmatic, but why not consistently expose a functional core as a matter of principle? Thanks for your consideration. Mario -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
