Let's start with NEWLINE: newline
is a word bound to a char!
value:
>> ? newline
NEWLINE is a char of value: #"^/"
That's Rebol's escape sequence for Unicode codepoint U+000A, commonly used as line feed ("LF") control code.
So your first example code [newline 1 2]
has nothing to do with the NEW-LINE function. It simply describes a block containing three values: newline
(a word!
), 2
(an integer!
), and 3
(another integer!
). If you REDUCE the block from your first example, you'll get another block of three values: char!
, integer!
, and integer!
:
>> reduce [newline 1 2]
== [#"^/" 1 2]
Now PRINT does not only REDUCE, it does REFORM (first REDUCE, then FORM) a block argument. FORM of a block converts the elements to a string representation and then joins those with spaces in between:
>> form [1 2 3]
== "1 2 3"
Putting those pieces together we finally know how to arrive at the output you are seeing for your first example:
>> basis: [newline 1 2 3]
== [newline 1 2 3]
>> step1: reduce basis
== [#"^/" 1 2 3]
>> step2: form step1
== "^/1 2 3"
>> print step2
1 2 3
So the question remains, why does the second example not print identically?
That's because FORM (used by PRINT, as described above) does not respect the NEW-LINE flag when converting from a block to a string.
This flag is "meta-data", not unlike e.g. the index position of an element within a block. So just as you don't have elements at index positions 8 and 6 just because you write a block like [8 6]
, you don't set the new-line flag for a position just because you happen to put an element there which is a character that on some systems represents a line break: [1 newline 2]
.
And this finally brings us to the last part of the puzzle: NEW-LINE? does not check if a given string represents a line break. It checks if a block (at its current position) has the new-line flag set.