[DOC] Differences between Red and Rebol
Table of Contents
- Local contexts for loops
- Binding to
- Invalid block selector returns
- Adjust time by setting timezone
- R2: not supported.
- R3: does not rebind functions to the new copy.
- Red: rebinds functions to the new copy.
>> o1: make object! [a: 42 m: does [a]] >> o2: copy o1 >> o2/a: 99 >> o1/m == 42 ;; Both R3 and Red ;; R3 does not rebind: >> o2/m ;; R3 == 42 ;; R3 ;; Red rebinds: red>> o2/m ;; Red == 99
Different names for datatype implementing the standard IEEE-754 64-bit binary floating-point format.
functionis a 3-argument function constructor taking a
vars(locals) block, and a
bodyblock. It is a mezzanine function.
functis a 2-argument function constructor taking a
specblock, and a
bodyare automatically (and deeply) collected as
/locals of the function. It is a mezzanine function.
functionis a 2-argument auto-localising mezzanine; collects
functis an alias for
functionis a 2-argument auto-localising native; collects
set-word!s and words of iterators
functdoes not exist.
Local contexts for loops
- R2 & R3: loops with words for counters or iterated values have a local context for them.
- Red: does not provide local contexts for loops, due to its high runtime cost: it requires rebinding (and eventually deep copying of the whole body block) each time the loop is about to be evaluated.
- R2 & R3: either
selfcan be used for binding words to the context of an object.
- Red: only
Invalid block selector returns
In Rebol, usage of invalid
word! selector in path throws an error, while in Red it returns
>> a:  a/b ** Script Error: Invalid path value: b ** Where: halt-view ** Near: a/b
>> a:  a/b == none
Historically, reflection on
object! values in R2 was done with
third functions, which return words, values and body of a given object, respectively. For
first returns argument words and refinements,
second returns body or
native! ID, and
third returns spec.
Later versions included mezzanine reflectors
spec-of for the same purposes, but retained previous conventions.
In R3, only
*-of reflectors can be used, and
self with object's back-reference are excluded from object's words and values blocks;
action! values yields
Red follows R3 convention, with an exception that
action!s results in an internal error and
any-function! values is not defined.
Both in R3 and Red
*-of reflectors are wrappers on top of dedicated
true if given directory exists. In Red, it returns
true if provided value syntactically looks like a directory, i.e. ends with a slash.
to-date function works with string values, but in Red this is currently not supported (note that this is subject to change). In either case,
load can be used instead of string conversion.
random on series shuffles its copy, but in R3 and Red series is modified in-place.
The values that get special treatment by
[block! path! string! url! file! error!]. Everything else is evaluated passively. This is by design, to eliminate variable arity (see here).
if in Red has no
/else (R2, equivalent to
/only (R3, returns
block! branch as-is) refinements.
In R3 and Red,
make generally doesn't accept
none in spec argument and raise an error, which is different from R2:
make integer! none ; == 0 make block! none ; ==  make file! none ; == %"" make tag! none ; == <> ...
Same applies to empty string:
make integer! "" ; == 0 (R2) make path! "" ; <empty path> ...
Also, there's a difference in
length? make hash! none
0 in R2 and
1 in Red.
last on empty series returns
none in Red and R3, but yields an error in R2.
take on empty series returns
none both in Red and Rebol, but
take/part ... 1 returns empty series in Rebol and
none in Red.
to-integer "" returns error in Red and R3, but
0 in R2.
file!loads file's content and return either one value or a block of values in Red and R2. In R3 it returns a string:
>> load %/c/file.txt == [abc def] ; Red & R2 == "abc^/def^/" ; R3
load %./returns a block of files and folders in R2 and R3, but not in Red:
>> load %/c/ == [%$Recycle.Bin/ %$WINDOWS.~BT/ %Boot/ %bootmgr ... ] ; R2 & R3 *** Script Error: transcode does not allow block! for its <anon> argument ; Red
read/lines/part behaves differently between Red and Rebol:
>> write/lines %file.txt ["one" "two" "three"] >> read/lines/part %file.txt 2 == ["on"] ; Red & R3 == ["one" "two"] ; R2 >> read/lines/part %file.txt 4 == ["one^M"] ; Red == ["one"] ; R3 == ["one" "two" "three"] ; R2
Note that this might change after 0.7.0 release.
Adjust time by setting timezone
Setting timezone of
date! value with
zone won't adjust time in either language. But in Red, such adjustment works with
>> d: now == 22-Dec-2018/1:53:52+03:00 >> d/timezone: 5:0:0 == 5:00:00 >> d == 22-Dec-2018/3:53:52+05:00
repend in Rebol is just a shortcut for the common
append ... reduce pattern. This means that you still incur the cost of an extra block produced by
repend is the fusion of
reduce, so that no intermediary block is created (thanks to the efficient
reduce/into call). This means that values are reduced and appended one by one in this case. It will behave the same way as
append ... reduce, unless you rely on side-effects, like above modifying the accumulating series while reducing. In such cases, just fall back on
append ... reduce in order to separate fully the reduction from the appending actions.
See the details here.
path!s are evaluated in R2 and R3 but not in Red:
>> b: [x 3] >> parse "aaa" [b/x "a"] == true (in R2 & R3) == false (in Red)
Integer after range values work in R2 and R3, but not supported in Red:
>> parse  [1 1 9] == true (R2 & R3) *** Script Error: PARSE - invalid rule or usage of rule: 9 (Red)
In Red, Meridian designations are not part of the
>> load "01:00PM" == [1:00:00 PM] ;Red == 13:00 ;R2 & R3 >> load "13:00PM" == [13:00:00 PM] ;Red == Invalid time error ;R2 & R3
This leads to below differences:
>> to time! "1:00PM" == 01:00:00 ;Red == 13:00 ; R2 == 13:00 ;R3
>> to time! "13:00PM" == 13:00 ;Red == none ;R2 == Error ;R3
select/skip returns a block (the record, see
? select) in R2 and a single value in R3 & Red:
>> select/skip [1 2 3 4 5 6] 1 3 == [2 3] ;R2 == 2 ;R3 & Red
Default value for refinements in Red is
false, while in Rebol it's
refinement! is currently not part of
any-word! as in Rebol:
>> any-word? /ref == true ;R2 & R3 == false ;Red
Red's and Rebol's lexers behave differently in some cases:
>> [/:a] == [/ :a] ;R2 & R3 == [/: a] ;Red
to-logic 0 returns
true in Red and R3, but
false in R2.
Some people think zero should be falsey, based on how many other languages do it, and their instinct was to follow how C did it. But C has no concept of real logic values. So what we need to ask is what makes the most sense in Red (Red/System is a different story, because it's a C level language).
Red chose to be consistent in how logic values are coerced, with only false and none mapping to false. Zero is a number, and no special case is made for it. Even
unset! coerces to
That said, you have an option.
Make creates a logic value of
false if the spec is a numeric zero, including floats and percents.
o: make object! [a: 1]
/pad refinement that sets remaining words to
none, but in Red that's a default behavior;
/some can be used to mimick Rebol convention and ignore remaining words.
>> set/some [a b]  reduce [:a :b] == [1 unset] >> set [a b]  reduce [:a :b] == [1 none]
/any works the same, and newly present
/only act according to their specs:
>> attempt [a: 1 set 'a () ?? a] == none >> attempt [a: 1 set/any 'a () ?? a] a: unset! >> block: [a 1 A 2] set 'block/A 3 block == [a 3 A 2] >> block: [a 1 A 2] set/case 'block/A 3 block == [a 1 A 3] >> set [a b][1 2] reduce [a b] == [1 2] >> set/only [a b][1 2] reduce [a b] == [[1 2] [1 2]]
unset! in Red and R3, but not in R2.
>> equal? () () == true (Red & R3) ** Script Error: equal? is missing its value1 argument (R2)
In R2 & R3,
?? takes a literal value and returns it back, so that it can be used inside expressions for debugging:
>> 5 - ?? 2 2 == 3
unset and only accepts words and paths:
>> ?? 1 *** Script Error: ?? does not allow integer! for its 'value argument *** Where: ?? *** Stack: ??
The rationale behind
unset is that Rebol console by default hid most of the values and one had to use
?? to see them:
>> f: does [something] >> o: make object! [a: 1] >> :f >> o >> ?? f f: func [something] >> ?? o o: make object! [ a: 1 ]
while Red console displays all the values:
>> f: does [something] == func [something] >> :f == func [something]
?? returning them would have led to output duplication, like this:
>> ?? o o: make object! [ a: 1 b: 2 c: 3] == make object! [ a: 1 b: 2 c: 3 ]
From within Red expressions
probe should be used instead:
>> 1 + probe 2 2 == 3