"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
) - There are... options!
