NEW-LINE Semantics, and NEW-LINE + INFIX functions

Newline semantics are a tricky idea in general.

I keep thinking that it's likely best if there is a generic line-continuation tool in the scanner.

Maybe it's backslash. The point is that backslash would not be something that would be LOAD-ed as a token, rather it would just act at scanner time:

>> transcode "a b^/c d"
== [a b
    c d]

>> transcode "a b \^/c d"
== [a b c d]

>> transcode "a b^/\c d"
== [a b c d]

So you could write it either way:

a b \
    c d

a b
  \ c d

In the model I'm contemplating, you'd still be able to use a GROUP! to continue an evaluation on another line:

x: (
    1000 + 20
)

But this would no longer be legal:

x:
    1000 + 20

You'd have to say:

x: \
    1000 + 20

x:
  \ 1000 + 20

Don't Like It? Dialect It.

You'd be free to interpret newline markers as you like in your own dialects.

 my-dialect [
     x: 
         1000 + 20
     nothing <stopping>
     you :FROM @doing what
     
     -ever- you want
 ]

Custom indentation is lost on loading, but BLANK! lines would be preserved

Inching Toward This, Bit By Bit...

I've been making rules about NEW-LINE markers. One thing is that if a function like RETURN or CONTINUE or QUIT are willing to take 0 or 1 arguments, then when it does take 1 argument that can't come from across a newline.

Another rule that seems to feel pretty sensible is don't allow infix across newlines.

But I anticipate that as these rules are converging on the likely-inevitable "arguments to a function can't span a newline (unless you put the argument in a GROUP! that starts before the newline)

1 Like

This has a performance advantage as well. In historical Rebol, if you see

x: 10
...whatever...

There's a lookahead step that considers ...whatever..., in case it's:

x: 10
+ 20

If we rule that out, we speed things up.

But It Would Rule Out ELSE/THEN on newlines...

You'd have to write this:

if condition [
   ...
] else [
   ...
]

And you wouldn't be allowed to write this:

if condition [
   ...
]
else [
   ...
]

That's a slight bummer. The new rules regarding BLANK! lines would still disallow:

if condition [
   ...
]

else [
   ...
]

And I'm fine with that being disallowed. But being able to separate an ELSE by a single line break has a nice aspect in that you un-crowd things:

if condition [
   bunch of code here
] else [
   bunch of code here
]

if condition [
   bunch of code here
]
else [
   bunch of code here
]

Not that you would want to use parentheses, but I'll point out this is a case where you couldn't use parentheses to get your newlines because that would block the visibility of the ELSE to infix lookahead:

if condition [
   bunch of code here
] (
    else [
       bunch of code here
   ]
)

Your only option would be the backslash:

if condition [
   bunch of code here
] \
else [
   bunch of code here
]

if condition [
   bunch of code here
]
\ else [
   bunch of code here
]

I don't actually think the first form of that looks so bad. Arguably it helps you realize the next thing is infix (with ELSE you know, but maybe other functions aren't so obvious if you don't know them)

I think the benefits of the "no-newlines in mid expression unless mitigated by lists" rule outweighs the advantages of newlined ELSE/THEN.

1 Like

I've tried implementing this.

One place where it becomes a tricky issue is generated code.

Part of this comes from the lack of intentionality in newline propagation when you're composing things. You may not intend to insert newlines, e.g. with:

data: []
append data spread compose [
   blah blah (10 + 20)
]
append data 'and

But right now, that gives you:

>> data
== [blah blah 30
    and]

At the current moment, you can change that by moving the end bracket:

data: []
append data spread compose [
   blah blah (10 + 20)]   ; <-- bracket here for `[blah blah 30 and]`
append data 'and

Proposed ideas would let you do this with a backslash:

data: []
append data spread compose [
   blah blah (10 + 20) \
]
append data 'and

While it does add a concern for generated code to worry about line breaks, I feel like being able to control the line breaks and give them semantic meaning in dialects is something that is higher leverage and more important than it has been given credit for historically.

So I'm more on the side of saying this is just something we need more ways to control, vs saying infix needs to pick up arguments from the prior line.

1 Like