Dropping rebValueQ() etc. in favor of rebValue(rebQ())

In case I haven't said it enough (mostly to myself), I'll say it one (?) more time: calling API functions which splice in values is very much like DO COMPOSE.

People may grumble when rebElide("append [copy reduce]", word); acts like:

do compose [append [copy reduce] (word)]

They may have forgotten they were in C (or JavaScript, or whatever), and at runtime in that language the variable names are gone. There is no "word"...just as "word" is gone after the COMPOSE is finished. So they would need:

rebElide("append [copy reduce]", rebQ(word));

Though they may grumble...at least they'd understand. On the other hand, they might get pretty mad if they get ['10 '20] out of the following if x and y are plain INTEGER!

REBVAL *coordinate = rebValue("reduce [", x, y, "]");

Do We Need both rebValue and rebValueQ?

The most foundational and pure API to give people is one that does what they asked. If you wanted a quote, you ask for it. If you don't, the value is left as-is. If it's in a context where you didn't want it to be evaluative and it evaluates...that's just a bug and you need to fix it.

I resolved to make operations like rebValue, rebElide, rebUnboxInteger etc. not add quotes for this reason. But to try and be "helpful", I thought to introduce auto-quoting versions like rebValueQ, rebElideQ, and rebUnboxIntegerQ that quote unless you explicitly ask for the quote to be removed with rebU().

If you had a lot of rebQ() calls in a given invocation, there was a performance advantage to making the Q-version of the call. And visually you weren't taking up as much space on a line.

But I'm on the fence looking at it in practice. This doubles a lot of the API interface, and now it doubles the doubling because there's C++ wrappers and C wrappers. In an API that was designed to be minimal and elegant, it undermines that elegance by appearing redundant.

One problem is that it adds an element of choice, which is a tax. Every time you make a call you wonder if you used the right one. And when you're in the middle of looking at a line of arguments you always have to scan back and wonder "is this in a Q call or a non-Q call".

Removing rebValueQ() and friends seems like the right move

There's a perceptual cost to making the API look larger and more cryptic. There's already a lot to learn, and then this cost is something anyone looking at the API or code samples will have to pay.

The performance advantage is fairly negligible compared to the overall cost of scanning/binding an API call. In cases that have no text portions to scan or bind, there's nearly zero advantage (for esoteric technical reasons I won't go into).

I'm not convinced the pain is reduced by that much by offering the alternatives. The main pain you are saved from is that when you have a lot of parameters you want to quote, you're saving characters.

If it seems too verbose to use Q a lot, there's always even more abbreviated shorthands:

#define Q rebQ

REBVAL *result = rebValue("some code", value1, "more code", Q(value2));

And the function of rebQ() actually is not to quote a single item, but to be able to enter "quoting mode" for an arbitrary number of items. It applies to splices, not loaded code from c strings. So if you need it rarely, you could say:

REBVAL *result = rebValue(rebQ("some code", value1, "more code", value2));

Obviously I have some conflicted feelings about this, or they wouldn't exist. But I'm leaning toward killing off the rebValueQ, rebElideQ, etc. variants. Mostly because I think it will make the API and callsites appear more orthogonal to those reading it.

If the new @ operator and its family of inerts work out, I think this need can often be replaced with @.

>> @foo
== @foo  ; THE-WORD! (maybe, to go along with THE?)

>> @ foo  ; standalone version acting as an operator
== foo

>> type of @
== the!  ; maybe? just pondering the concept out loud...

Anyway, if you have code like this fragment from the console:

    else if (rebDidQ("word?", e)) {  // recognized "virtual key"
        uint32_t c = rebUnboxChar(
            "switch", rebQ(e), "[",
                "'escape [#E]",

                "'up [#U]",

You could instead say:

    else if (rebDid("word? @", e)) {  // recognized "virtual key"
        uint32_t c = rebUnboxChar(
            "switch @", e, "[",
                "'escape [#E]",

                "'up [#U]",

It only works in evaluative slots... since it doesn't actually get involved in adding quote levels on anything. But it would be fast, on par with rebQ(). And this is what most rebQ() are used for, so I think it's a good option. It calls attention to it well enough that you can see something is going on, and is easier to read IMO.

I think this points to another sign that the rebValueQ() routines are going away. There were some developments in Sea of Words pointing to the idea that rebArg() and rebArgR() would be going away... replaced by native functions actually searching their parameter list by name.

Design....takes...time. :mantelpiece_clock: