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 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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to