nedap.one.api/one
is a clojure.core/cond
replacement, using its same exact syntax. It avoids problems with cond
, case
, if
et al.
As said, one
has the same exact structure and semantics than cond
. In fact when clojure.core/*assert*
is false, it will macroexpand to a plain, unadorned cond
.
Consequently,
one
has zero cost in production.
What's the difference?
All conditions are evaluated, and it is asserted that exactly one is true
Duplicate conditions are forbidden
(cond 1 2, 1 2)
has the 1
condition duplicated. clojure.core/cond
would happily compile that.cond
(and condp
)cond
to have sequential semantics
nil
.
case
(let [a 2] (case 2 a :win)) ;; Error - no matching clause
if
if
s).if
s can get intrincate, while a cond
or case
are flat.
Flat code tends to be easier to understand/maintain.(if (= thing :blue)
"Your eyes are blue"
;; Programmer thinking: it's not :blue, so it has to be :brown
"Your eyes are brown")
;; let's say the programmer accounted for :blue and :brown cases, which are in fact
;; the two only possible cases _today_ in a given domain.
;; Tomorrow this code might break as requirements change (new colors are introduced), because it used `if`.
They are flat, non-sequential and have arbitrary dispatch (unlike case
's). However, they tend to be verbose/overkill for self-contained tasks: a single 4LOC defn should't become 1 defn plus n multimethods.
Similarly, dispatching conditions->consequences via a hashmap is not a very usual pattern, nor a concise one.
Sequential semantics? | Implicitly defaults to nil? | Acceptable dispatch values | Extensible? | Simplified dispatch cost | Simplified invocation cost | |
---|---|---|---|---|---|---|
cond | yes | yes | Expressions | no | O(n) | Low |
case | no | no | Compile-time constants | no | O(1) | High |
if | (yes, if nested) | (yes, if no else ) | Expressions | no | O(n) | Low |
hashmaps | no | yes | Expressions | yes (they can be merged) | O(1) | High |
multimethods | no | no | Expressions | yes | O(1) | High |
one | no | no | Expressions | no | O(n) | Low |
There's no clear winner (but there are clear losers, in terms of complexity: cond
, if
, case
).
I would recommend one
when no need for extensibility is foreseen, and keeping the code inline + straightforward would be a win in maintainability.
[com.nedap.staffing-solutions/one "1.1.0"]
Only nedap.one.api
is meant for external consumption.
Please browse the public namespace, which is documented, speced and tested.
Some quotes from Simple Made Easy:
Syntax, interestingly, complects meaning and order often in a very unidirectional way.
Fold is a little bit more subtle because it seems like this nice, somebody else is taking care of it. But it does have this implication about the order of things, this left to right bit.
As one can observe, Rich repeatedly denounces sequentiality as a source of complexity.
i.e., how is:
(one
x 1
(not x) 1)
...better than...
(if x
1
2)
...?
one
's repetition can make code clearer
not
, or
, and
) between clausesone
with a let
, extracting the repetitive parts.(put-clojure-indent 'one 0)
(add-to-list 'clojure-align-cond-forms "one")
Copyright © Nedap
This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close