In the spirit of going over and reviewing various inventions, and deciding if they were good or bad, here’s one I think is…a bad one.
Backstory: The idea of creating “question marked” versions of various functions originated with IF?. Due to the workings of historical Rebol’s IF, it was not possible “from the outside” to know whether it took a branch or not. But some code tried to leverage the #[none]-returning nature of an IF that didn’t take its branch, even though technically a taken branch could return none, false, void…
At one moment in time, there was a behavior change:
>> all [1 (if 1 > 2 ) 4] == #[none] ;-- R3-Alpha == 4 ;-- an early Ren-C behavior
Ren-C was interpreting a failed IF as “opting out” of its contribution, as if it were not there. R3-Alpha/Rebol2 were tying together the failing of the condition with the idea that failure should propagate out.
UPDATE: The design is no longer to opt-out when the condition fails, rather the null that is returned is conditionally false. That means the ALL above would itself evaluate to null.
At the time, I believed that opting out was the more interesting behavior. But trying to answer every potential criticism, I added to conditionals like IF a /? refinement…which asked the native to return a LOGIC! of whether it took the branch or not, vs. returning the evaluative value of the branch.
There’d also been a history of people wanting to get LOGIC! variables out of something like FIND. They would use it even when it was not necessary, so they would write if found? find … even though the IF was perfectly capable of dealing with a BLANK! to mean nothing was found.
Because CHAIN and SPECIALIZE had been invented just recently then, I was eager to test them. And so I was busy trying to show that you could make all these function variants easily while reusing the same frame. FIND? could be written in just a few lines, have all the same parameters, and return a LOGIC!.. so if find? … could take the place of IF FIND? FOUND…
—But I feel like I created a monster.—
People started using these in places they really weren’t necessary, just to try and drive home that it was a test that could succeed or fail. Compare:
if all? [ find? haystack needle select? data key ][...]
if all [ find haystack needle select data key ][...]
Not only would the second case be slightly faster (by not having to go through a specialization layer), it looks cleaner. And as we learned with LENGTH?, if you just go throwing question marks everywhere they start to lose their meaning. Largely things that ended in ? were generally cheap tests with no side effects, and here we were starting to get WHILE? loops or IF?s that ran branches.
I think the whole point of nulls/blanks in Rebol is something that could be taken for granted and used as conditionally false. And these operations were a mistake to introduce.
For the cases where you actually do need a LOGIC!, besides TO-LOGIC we now have a sort of interesting word in the form of DID, as the positive analogue to NOT. Maybe it isn’t perfect for all cases, but did select … or did find … or even did any […] are all superior to SELECT?, FIND?, ANY?.
Moreover, I haven’t really found all that many legitimate uses for the likes of IF?. Plus it’s now possible to tell if a branch was or wasn’t taken with null? if condition […] or
any-value? if condition [...] (someday shortened to value? if condition […]) The kind of person who would be taking advantage of IF’s properties in this respect has way more options if they just react to the output of the IF.
So I think we should retire these specializations.
They are cruft, and an example of gratuitous early use of specialization and chaining. It was nice that they were around in the early days of those abilities, and helped debug that and show what’s possible. But they’ve overstayed their welcome, and need to go.