One question that comes up fairly often with new users is why if [var = value] […] doesn’t do what they expect.
We know that blocks are truthy, and passing a literal block to an IF will not run the code in the block. They should have written if (var = value) […] or just plain if var = value […]. But this isn’t obvious to a newbie.
When I’ve encountered this situation myself, it’s usually because of changing a WHILE into an IF, or something of that sort. Of course, I know why a WHILE puts a block around its condition and an IF does not…but for a new user that’s certainly non-obvious.
Hence, VALUE_FLAG_UNEVALUATED was born
I had the idea that values would have a bit on them that would say whether they were the product of an evaluation, or just literal. Hence when IF ran, it could tell the difference between:
block: [a b c] if block [...]
if [a b c] [...]
The former it would allow, the latter it would prohibit with an error. This seemed like a good thing.
Does it do more harm than good?
You probably shouldn’t write if [literal block] in your code (unless you were writing a test, or plan on transforming it before execution). Yet you might well want to do this in a composition.
compose/only [... if (conditional-expression) [...] ...]
If that conditional expression is a literal block, then do you want to get an error on it?
And really, what if someone does write:
condition: [var = value] ... if condition body
If they intended that condition to execute, that’s a mistake that wouldn’t be caught. So here we have the check impeding experts…and not protecting new users as thoroughly as one would hope.
Nearly every safety feature has shown to be not worth it
Because Rebol is subtle and can be difficult to debug, it has been tempting to throw in various safety mechanisms. But nearly all that have been tried have been thrown out, instead addressing the relevant concern through a different angle.
There’s no question that the existence of VALUE_FLAG_UNEVALUATED and maintaining its state makes the evaluator code more complicated. Yet I’ve found being able to read it as being helpful in some cases when debugging or deprecating APIs. It’s likely good to keep the feature and let functions know this property of their callsites if they find it necessary.
But should things like the protection of IF and other conditional clauses be in the box, or should it be part of an adapted definition in a “training wheels” module…not enshrined in the mainline code? (For that matter, should the website demo use training wheels mode by default, if it existed?)
I think I’m leaning toward making this a training-wheels-only feature, and having the stock IF (CASE/etc.) not error on literal blocks. Of course, the training wheels would have its work cut out for it to emulate every conditional test in a CASE statement, it would basically have to reimplement CASE. So this is a fairly heavy change.