COND vs. OPT — Opting Out vs. Opting In w/Nothing

"Opting out" and "opting in" show up as distinct intents.

Consider how ENVELOP handles a VETO.

>> envelop [[]] veto
== \~null~\  ; antiform

It gives you a NULL back, assuming you wanted to "opt-out" of the operation entirely:

But if you wanted to "opt-in" (in an empty sense) you can do that with an empty splice. This isn't any particularly "weird" behavior, it just naturally falls out from the nature of splicing.

>> envelop [[]] [a b c]
== [[[a b c]]]

>> envelop [[]] spread [a b c]
== [[a b c]]

>> envelop [[]] spread []
== [[]]

>> envelop [[]] none
== [[]]

"OPT" Also Lets You Opt-In With Nothing

OPTIONAL (shorthand OPT) is a generic operation for producing voids from nulls.

>> opt 1020
== 1020

>> opt null
== \~,~\  ; antiform (ghost!) "void"

So you can pass voids to ENVELOP as well and get nothing out:

>> envelop [[]] if 1 = 2 [<unused>]
== [[]]

>> item: null

>> envelop [[]] opt item
== [[]]

Several functions behave this way... do nothing, but return the input.

>> append [a b] ()
== [a b]

CONDITIONAL (COND) vs. OPTIONAL (OPT)

COND is an arity-1 conditional operator. The condition and the branch are the same thing... if you pass it null you get VETO, and if you pass it anything else (that isn't a TRASH! or ERROR!) you get the thing you passed in:

>> cond null
== ~(veto)~  ; antiform (pack!)

>> cond <d>
== <d>

>> append [a b c] cond null
== \~null~\  ; antiform

>> append [a b c] cond <d>
== [a b c <d>]

So OPT is similar, but it produces a void on null:

>> opt null
== \~,~\  ; antiform (ghost!) "void"

>> opt <d>
== <d>

>> append [a b c] opt null
== [a b c]

>> append [a b c] opt <d>
== [a b c <d>]

While these are useful, observe also that unlike Redbol's "falsey NONE", Ren-C's empty splice is the positive sense of emptiness, so it is truthy. You can make it fall out of an ANY or ALL...

>> envelop [[]] opt all [1 < 2, 10 < 20]
== [[]]

>> envelop [[]] all [1 < 2, 10 < 20, none]
== [[]]

OPT IF, OPT SWITCH, etc: NONE-making Conditionals

OPT is willing to turn a GHOST! into a NONE (as well as a NULL). Which means it can be used as an adapter to turn branching structures to being friendly.

<cond> and <opt> Function Arguments

There is a cool feature designed to help you easily implement this behavior in your own functions, which is to label your function arguments as being [<opt>]

If an optional argument receives a VOID, then it will be received as NULL in the body--making it easier to test for (and less likely to use on accident, mistaking it for a value):

>> bar: proc [x [<opt> integer!]] [
       if not x [
           print ["X is NULL, so it must have been none!"]
       ] else [
           print ["Calling foo!, x is" x]
       ]
   ]

>> bar none
X is NULL, so it must have been none!

>> bar opt null  ; hence why it's an <opt> parametr 
X is NULL, so it must have been none!

>> bar 304
Calling bar!, x is 304

Function arguments can be both <cond> and <opt> (such as the second argument to APPEND).

It Makes A Lot Of Sense

There is indeed to me something kind of stronger about the word "conditionally" over "optionally".

If I told you I optionally appended material, vs. appending was "conditional" on the material, which sounds like it's softer?

  • There are... conditions. (menacing :enraged_face: )
  • There are... options! :smiling_face_with_sunglasses:

I will thrown in that COND has gone back and forth with the name "WHEN".

It's a friendlier word that seems kind of appropriate in some uses.

>> item: 'd

>> append [a b c] when item
== [a b c d]

>> item: null

>> append [a b c] when item
== \~null~\  ; antiform

And you can kind of see it being fitting in PARSE too:

parse "aaa" [when (mode = <a>) some "a" | ...]

Maybe it makes sense in these other short-circuit situations as well:

>> stuff: spread [a b]

>> envelop [[]] when stuff
== [[a b]]

>> stuff: null

>> envelop [[]] when stuff
== \~null~\  ; antiform

You can say that the "WHEN" is controlling, it says "if this isn't non-NULL, you don't even run it". It makes sense to see it that way.

But the English-ness breaks down a bit if you do somtehing like use NULL literally, to where it sounds like "do the thing when it is null null":

>> append [a b c] when null
== \~null~\  ; antiform

To be fair, that is just how things work should you write null literally... in every logic situation:

if null [...]  ; huh? is it asking if the block is null?

And it starts to read more weird than COND, I think, with things like type tests:

if integer? when var [...]

I've gone back and forth on it, and felt like CONDITIONAL makes sense for this. And WHEN could be useful elsewhere--not to mention that it doesn't really seem "arity-1". So COND is where it has settled.