Death to BAR! (Long Live Expression Barriers!)


Rebol expressions have a habit of getting hard to read when you put them all on a line:

if all [integer? x even? x x > 10] [print "confusing!"]

You could put the expressions in GROUP!s:

if all [(integer? x) (even? x) (x > 10)] [print "confusing!"]

But that looks a bit cluttered. And if you’re going to be byte-conscious (and CPU-cycle-conscious), each GROUP! is a distinct array series, and represents a separate recursion in the evaluator. You’ve quadrupled space and CPU usage. You’ve also squandered GROUP! for any COMPOSE operations that you might have wanted to use it for.

Some people (@gchiu, and I’ve seen Gregg do it) double space to get around it:

if all [integer? x  even? x  x > 10] [print "better?"]

That’s not a terrible answer, though I think it looks like a mistake. And there’s no enforcement of if you’re right about where the expression breaks are or not, you can get it completely wrong:

if all [integer?  x even? x x  > 10] [print "nonsense..."]

Meet Expression Barrier

Expression barrier is a postponing-enfix invisible action.

All that means is that it won’t run in an argument slot, it demands your evaluation be at a “neutral” point before it runs and takes the left-hand product. This finicky-ness is perfect for the task:

>> (1 + 2 | 10 + 20)
== 30

>> (1 + 2 |)
== 3

>> (1 + | 2)
** Script Error: + is missing its value2 argument

For practical purposes, it looks like an END to a variadic (much like a THEN or ELSE does now, to enforce consistency between variadic and non-variadic forms). Which gives a pleasing result:

foo: func [x [integer! <...>]] [
    sum: 0
    while [not tail? x] [
        sum: sum + take x

>> (z: foo 1 2 3 | 4 5)
== 5

>> z
== 6

BAR! is not a Special Datatype Anymore!

In the early days of Ren-C, there was little hope for implementing what expression barriers wanted without a specific feature. It was tried, e.g. an early attempt in R3-Alpha at getting an expression barrier was |: does []. It was non-ideal, but since unsets were ignored by ANY and ALL you got at least a smidgeon of “invisibility”:

r3-alpha>> |: does [] 
r3-alpha>> all [true | true | 1020]
== 1020
r3-alpha>> any [false | false | 1020]
== 1020

Red considers #[unset] to be truthy, so this doesn’t work:

red>> |: does [] 
red>> all [true | true | 1020]
== 1020
red>> any [false | false | 1020]
; no result

The overall shape and design of Ren-C tried to embrace the concept of “null as invisible” until that really didn’t work, leading to today’s designs (falsey null, logically ambiguous void). None of it has much to do with expression barriers…which have turned out to have more in common with COMMENT and THEN/ELSE than anything.

In any case, | comes back now as a WORD! for the best of reasons: all the magic is now in userspace features. So mark down one fewer incompatibility point with Rebol2 and friends…and one more victory point for the Ren-C design.

(I will postpone my examples of cool uses for postponing enfix operators for another thread…!)