dbj.cond is one very flexible thing. But here in lies its hidden complexity: the flexibility sometimes brings benefits hard to understand. And what is hard to understand one tends to avoid.
So, I have decided to catalog what I am calling “shapes” of dbj.cond
. They are not “use cases” (UC). UC’s are showing concrete real life examples of dbj.cond
usage. While Shapes are generic description of an finite number of coding idioms, shaping dbj.cond
usage.
In this dbj.cond shapes catalogue each shape has a name, javascript pseudo code and a diagram.
dbj.cond shapes catalogue
[nextpage title=”The COND”]
Lisp syntax of the COND statement is this:
(COND ((condition_1) (outcome_1)) ;; any number ((condition_2) (outcome_2)) ;; of cond/outcome ((condition_3) (outcome_3)) ;; pairs (T (outcome_4)) ;; otherwise )
Result of condition is true or false. If true it’s pair value is returned and COND stops. If none is true the value of the last pair (T (value_4))
is returned. ‘T’ is true in LISP.
In JS syntax the equivalent is this.
if ( condition_1 ) { outcome_1; } else if ( condition_2 ) { outcome_2; } else if ( condition_3 ) { outcome_3; } else { outcome_4; }
dbj.cond
has as a first argument the input value. so that each “condition” from above is actually a comparison of that input value to whatever we need to compare. To shape it up to behave like a basic LISP cond we simply give ‘true’ as the input value.
dbj.cond ( true, /* the input */ condition_1, outcome_1, condition_2, outcome_2, condition_3, outcome_3, outcome_4) ;
Were conditions are any JS expressions resulting in true or false.
Basic LISP cond reversed
Since JS can be obligatory mind-bending we will introduce an sub shape to this which does exactly the opposite. It stops the conditional multi selection if the condition met is false.
dbj.cond ( false, /* the input */ condition_1, outcome_1, condition_2, outcome_2, condition_3, outcome_3, outcome_4) ;
If any of the expressions representing the conditions above yields false, dbj.cond
stops and returns its value sibling. Lisp COND can not do that.
[nextpage title=”Standard”]
Each and every dbj.cond shape conforms to the above diagrammatic representation of its internal processing.
It is important to note the “comparisons”. The dbj.cond comparisons are performed by primary and secondary comparator functions. If secondary is set that is.
// // set optional primary and // optionally secondary // comparator functions // if neither is given the current is unchanged // return array of the current comparators // [ primary, secondary ] // dbj.cond.setcmp( primary_cmp, secondary_cmp ); //
[nextpage title=”The Functional”]JavaScript (JS) has a function as the “first class” object. Nothing is stopping us to use functions in place of any argument to the dbj.cond()
, some arguments or in place of all arguments that is.
Canonical Functional shape of dbj.cond
// dbj.cond Functional shape dbj.cond ( input_provider_function, /* the input */ condition_function_1 , outcome_function_1, condition_function_2 , outcome_function_2, condition_function_3 , outcome_function_3, /* there can be any number of condition/outcome pairs */ outcome__function_4) ;
Any shape of mixing functional and non functional arguments is of course possible. As long as the underlying comparator can handle them.
Please keep in mind the underlying comparators. In the case of using any variant of this dbj.cond shape comparator must be able to compare functions.
And this is where one meets head on, so called JS minefields, like this one:
var A = function () { return 2 }; var B = function () { return 2 }; function C () { return 2 }; function D () { return 2 }; // two function variables are strictly equal A+"" === B+"" /* true */ // while two same functions are not C+"" === D+"" /* false */
Moral of the snippet for comparator writers: It is hard to decide how to compare two functions in an browser agnostic way and in the EcmaScript standard version, agnostic way too.