What to do with the lone ? character


#1

Historically Rebol used ? as a synonym for HELP.

I type the unshifted sequence h-e-l-p as fast (maybe faster) than the combined sequence shift-/ to get the ?. Not only that, a console dialect could just as easily take H for help as it could take Q for QUIT, while keeping these abbreviations out of the language itself.

So considering the rare number of single-character sequences and symbols available, it seemed a waste to steal ? away from some purpose you would actually find common use for in user code.

My first idea was that since we use things suffixed with a ? to mean a logical test for something, why not make a lone question mark some very common existential test? My first idea was to make it a quoting operator testing variables for void, so that ? var could mean set? 'var.

if ? var [
   print "var is set"
] else [
   print "var is not set"
]

One thing that worried me is that if? var […] is different, meaning “give me back a LOGIC! of whether you ran the branch or not, don’t give me the branch-result-or-a-void”. But, that’s hardly the only space-significance issue out there, and one of the least surprising. Also, I doubt people will be using IF? all that often. I really haven’t needed to use it yet. :-/

UPDATE circa 2018: The IF?, CASE?, SWITCH? etc. variants no longer exist, due to better ideas.

I still think this operator choice is a pretty good idea. I’ve tried other things, like seeing what could be done with it as a postfix operator, like it was punctuating with a question mark. But never felt like using that. However, I would certainly use ? var a lot… every day.

But how do other languages use it? C-inspired languages make it a ternary operator, which when combined with a : becomes more-or-less an EITHER. So:

 x = condition ? expr1 : expr2;

Is basically equivalent to:

x: either condition [expr1] [expr2]
x: if condition [expr1] else [expr2]

While we can do some magic with variadics these days, Rebol doesn’t encourage constructs that scan ahead for other delimiters. (Notably, that is not how THEN or ELSE work, which is part of what makes them awesome.)

So I don’t know if doing a ternary operator would be very good. However, with the recent advances in left-hand-non-tight-enfix–and the death of the old meaning of IF/ONLY as “block means block”, we might consider an infix binary operator to take its place.

>> x: 1 < 2 ? [data]
== [data]

>> x: 1 > 2 ? [data]
; no result

It would then share heritage with the ternary operator in the sense of being conditional, but bring something to the table that IF does not with the “return the right hand side as-is” property.

spaced ["(CONSOLE" (unless proto-skin/updated? {not}) "updated)"]
    =>
spaced ["(CONSOLE" (not proto-skin/updated? ? {not}) "updated)"]

Well, maybe. It does run up against that question of whether 0-arity things should end in ?. If they do, this will create a bit of visual unhappiness with postfix operators called ?. But what if it wasn’t like that?

spaced ["(CONSOLE" (not proto-skin/updated ? {not}) "updated)"]    

Something to think about.

Digging around in other languages, Haskell leaves it a legal operator for you to define how you wish (so does Rebol, you could still override it if you want). Rust calls it a “unary suffix operator which can be placed on an expression to unwrap the value on the left hand side of ? while propagating any error through an early return”, or at least proposed to be one. That doesn’t have a parallel in Rebol’s world exactly.

What do people think? I definitely don’t think this should be wasted on a help synonym, at the detriment to all code everywhere…


#2

Why not use ?? as set? and then we can have

>> x: 1 < 2 ? [data]
== [data]

I like this better than if because I don’t have to indent and there’s less to read.


#3

I’m a touch-typist and so my h-e-l-p is also quick. However my chord usage is ingrained and so shift-/ is still much quicker for me :stuck_out_tongue:

While ? is entrenched into my muscle memory for console usage I’m OK if it being used for an operator. It’s easy to fix with console shortcut and/or retrain my muscle memory to use a H shortcut instead.

I agree with @gchiu with using ? for above. So definitely a :thumbsup: from me.

Not sure about ?? for set? though? Prefer it to be an operator.

BTW - I do have some code that uses old CASE/ONLY. I have been thinking about replacing them with new CHOOSE func which replicates old CASE/ONLY…

>> choose [1 < 2 [data] 1 != 1 [foo]]
== [data]

… but could do this with suggested ? like so:

>> any [1 < 2 ? [data] | 1 != 1 ? [foo]]

… but possible a case for having both :slight_smile:

Yeah that’s not nice to look at :frowning: However I do like my 0-arity flags?, so I would just keep to UNLESS example above that or change it to:

spaced ["(CONSOLE" all [not proto-skin/updated? {not}] "updated)"]

Probably something like && would be better for this.


#4

That’s interesting, and actually useful.

I guess the fact that this operator is a conditional in so many languages…not just C ones but even in languages like Perl and Ruby…means it’s sort of in the zeitgeist for people to expect something like this.

Okay, well being useful, plus two votes against my “leaning toward SET? 'VAR” half-vote wins. At least enough that we can experiment with it a while and see if we like it.

Though you could use it with ELSE and get ternary if you wanted, it doesn’t seem very symmetrical… since ELSE would run a block, and isn’t as forgiving by default on expressions. On a whim, I added ?? for this

>> 1 > 2 ? [hi] ?? [bye]
== [bye]

>> 1 < 2 ? [hi] ?? [bye] 
== [hi]

>> 1 < 2 ? 3 + 3 ?? 4 + 4
== 6

>> 1 > 2 ? 3 + 3 ?? 4 + 4 
== 8

?? tests for a value on the left, passes it through if it’s not void, otherwise gives you the right as-is. You could do this indefinitely…

>> 1 > 2 ? [a] ?? () ?? () ?? [x] ?? () ?? [y]
== [x]

(For that matter, you can mix it all up… with THEN and ELSE and ? and ?? and THEN* and ELSE*… and wind up with some really unusual stuff, I bet.)

All right weirdos, try it out and see how you like it. :slight_smile:


#5

I’m convinced. CASE/ONLY was probably the most practically useful of the old-/ONLYs.

Your wish is granted. All I ask in return is that you write me some tests. :slight_smile:


#6

For anyone following the thread, we’ve decided to try ?? and !! instead of ? and ??. It stands out a little better. Compare:

1 > 2 ? [a] ?? () ?? () ?? [x] ?? () ?? [y]

1 > 2 ?? [a] !! () !! () !! [x] !! () !! [y]

The latter also lines up with Perl6, somewhat, where it had formerly been ? and : but this was deemed better “after long thought”.

This means ? var is free to experiment with for set? 'var, so we’ll give that a shot…


#7

So, does this mean that convergence will result in Ren-c looking like Perl?


#8

If there are any good ideas in it. That looks like one, but a purely optional one. You can mix and match.

condition ?? value-not-executed-if-block else [code]
if condition [code] !! value-not-executed-if-block

It’s rather interesting. And I still am pretty much wanting the # pound followed by space comments. Semicolon is never enough for me, I always have to do something dumb, like ;; or ;--, neither of which please me.