DEFAULT exists to run a block of code to give something a value if it doesn't have one already.
>> unset 'x
>> x: default [10 + 20]
>> print x
30
>> x: <some-tag>
>> x: default [10 + 20]
>> print x
<some-tag>
With DEFAULT
, the basic version treats both blanks and voids as "nothingness" and DEFAULT*
only considers a void to be truly nothing, so it won't overwrite a blank.
@gchiu at one time asked for an "anti-default". Rather than make the decision of whether to overwrite or not based on the content of the variable and only sometimes evaluate the block...always evaluate the block, then decide whether to overwrite or not based on the result of that evaluation.
The name suggested for it was UPDATE:
>> x: <some-tag>
>> x: update [()]
>> print x
<some-tag>
>> x: <some-tag>
>> x: update [10 + 20]
>> print x
30
This seems very useful to me, especially when used with conditionals. While simple conditionals can move assignments into the block of code, e.g. x: if c [v]
=> if c [x: v]
, more complex instances might have several points they'd have to selectively do the same assignment:
number-of-variants: update [
case [
whatever1 [do some stuff | 1020] ;-- update for this case
whatever2 [do some stuff | blank] ;-- don't update in this case
whatever3 [do some stuff | 304] ;-- update for this case
] ;-- don't update if no matches
]
As with DEFAULT it would ordinarily consider the right hand side evaluating to blank to be the same as void, e.g. not a new value, and a UPDATE*
would overwrite even if it was blank...only not if void.
But what we noticed was that UPDATE has been taken for a somewhat esoteric port action that I don't think anyone is using at the moment.
This raises a bigger question about what exactly the plan is about taking generic global namespace words away from the language and generalizing them in case a port might want to use them. I said this:
What one notices with the "word space" in Rebol is that there has been a sort of ambition to take generic words and in the grammar prefix them before things. So if you say update X it can be polymorphic where x is a port or a string or whatever.
So it seems that swiping something like the word UPDATE for an enfixed operator is bad. But yet, even without enfixing, this genericity runs up against another Rebol policy of fixed arity. If arity is fixed, how many parameters does the UPDATE operation that works for all time take?
The cheat is to make it arity 2, and then worst comes to worst, you find some way to fit whatever you want to say into a block. Or add refinements that somehow only work for some targets and not others.
Having previously expressed skepticism of the refinement model and other things about ports, I really do wonder if DO is being overloaded with a task it is unfit for, in a language that's supposed to be about dialecting. Should there be a generic operator, like
foo <- [ ... ]
and it just writes instructions at ports, where they're expected to know their "language" and arity of instructions?