Notable facts about Rebol programming language

rebol programming-language

Rebole is an unusual open-source (from v3) functional programming language with infix operations.

Rebol was closed/open source

The documentation says that core component of Rebol (I think it contains interpreter and a few native functions) is closed:

This is what makes REBOL operate identically over all systems and devices; therefore, we're strict about it.

And everything else (standard functions lib, for example) are open.

But there is official github repo.

And there is a compilation guide from the author of Rebol.

Rebol has minimalist "toolset"

Rebol is an way under 1MB single binary executable file.

Rebol has minimalist file name extension

Rebol scripts (called rebols!) has r file name extension. The shortest possible if not considering an empty extension as in bash. (Through r3 is considered for Rebol 3 now.)

Rebol has liberated identifiers

The language has somewhat significant white space, because identifiers can include symbols like +, - or ?:

a + b - c  ; arithmetic expression
a+b-c      ; identifier
print length? "example"    ; 7

Also identifiers can start with non-letter. So + is valid identifier (an word in Rebol).

Rebol has rich set of literals

Rebol allows to create tuples using .:

3.1.5           ; version numbers   ; colors      ; network addresses

But I can not understand how does it differentiate them from floating point literals, like 3.14 (they are supported by Rebol.)

The language has built-in datetime literals:

20-Apr-1998/12:32        ; date and time
20-Apr-1998/12:32-8:00   ; with timezone

URL and other "special strings":

<div class='marx'>

All code in Rebol is data

Code is data:

>>> if false [bla bla]

Not very interesting for functional people, but very interesting for others.

In general the evaluation of values of "variables" is lazy:

>> sizes: [small med big]
== [small med big]

>> print sizes
** Script error: small has no value
** Where: print
** Near: print sizes

>> sizes
== [small med big]

Rebol has special prefix and postfix colon "operators"

Colon is assignment operator when placed right after identifier:

blk: [print 1 + 2]
if true blk
; 3

And it is an quoting operator (like in Ruby or Julia) when placed right before identifier:

>> print print
Script error: print is missing its value argument

>>> print :print
make native! [[
    "Outputs a value followed by a line break."
    value [any-type!] "The value to print"

In both cases colon creates single fused value with the identifier it is applied to:

length? [a: 1]
length? [:a 1]
length? [a = 1]

Equals operator is used for comparison that is a good thing, no more =/== mistakes.

Rebol has unquote-like operator

Code is data that is executed implicitly in many cases, but also can be executed explicitly by do operator.

do [print 1 + 2]   ; 3

Blocks [] are passive lists like in clojure.

do also can execute strings or files (later - by file name literal).

Rebol functions have refinements

Refinements are additional modes of existing functions:

print copy "example string"
; example string
print copy/part "example string" 7
; example

The (manual)[] says it makes names easier to remember.

I don't know if it's the case, but it can make functions more autocomplete-friendly. Like with object members in OOP languages.

We also did not use dot because we didn't want to lose the ability to specify file names as refinements (with suffixes that use dot, like that shown above).

So I assume the refinements can be dynamic, not totally predefined (?).

Refinements replace boolean arguments that are false by default, and specified not by passing true somewhere in the arguments list but by specifying a name of refinement. I think it's good, though it leaks names of parameters so can potentially create a problem in case of refactoring.

Rebol programs can be a complete mess

Any Rebol program can be written as one-liner

>> print "reading web page..." data: read print length? data
reading web page...

Many languages more or less have this property, for example, any JavaScript program can always be minified to a complete mess, but Rebol does this without parentheses and semicolons!

Rebol has linear precedence for infix operators

All operators have the same preference:

print 1 + 2 * 3 + 4 * 5

We've found that for most expressions, linear precedence works as well or better than multilevel precedence, and you don't have to memorize all the precedence rules (which once you add comparisons and logic can become quite complex and few people remember them.)

This linear precedence is interesting but creates problems because the priority of operations is still higher than priority of functions:

if (length? "a string of chars") > 10 [print "ok"]

Rebol has two ifs

There are two if-like expressions: if and either. First is binary (two arguments - condition and expression), second is ternary (condition, true branch expression, false branch expression).

I think this approach was selected because all Rebol functions must have fixed arity, so we can not have two overloads of if or if with optional argument.

The manual says:

A common mistake is to add a second block to if or forget the second block on either. These are both wrong, but they may or may not cause a run-time error:

So may be two different names for if and if-else allow programmers to avoid this mistakes too.

Rebol has (no) local variables

All variables are global by default and one creates local variables through a hack:

print-it: func [/local str] [
    str: ""
    insert str "ha"
    print str


And even with this hack the value is static in C sense:



The tutorial guide does not state it but full Rebol 3 docs say that there is actually a way to create local variables:

print-it: function [][str][
    str: ""
    insert str "ha"
    print str


But this does not run for some reason:

** Script error: str has no value
** Where: print-it try do either either either -apply-
** Near: print-it

May be the feature is work in progress...

Rebol has no closures

Captured variable values will change on every call of outer function:

make-timer: func [code delay] [
    timer: func [time] [wait time + delay]

Here delay will change on make-timer call, affecting timer function.

This is unusual for functional language.

Other facts

It seems like collections have state - current index position. But I was unable to check that in Rebol 3.

There are type literals in Rebol like

none! number! string! error!

and so on and they can be assigned to variables!


Rebol is a bit unusual dead programming language.

It has no proper lexical scope and no closures, and seems to have no proper local variables.

But has very minimalist syntax (the one of the purest I've seen) and has some interesting ideas like refinements and built-in literals for many types of data. Here it is similar to Bosque - a new programming language from Microsoft Research. Also Rebol shows an example of infix operators in lisp-like languages.

Another interesting idea is with colons eliminating the == problem.

Btw formal parameters in function declaration can have prefix colon operator too - in this case argument will not evaluate.

For example, this will fail with script error

f: func[f][ print f ]
f print

because print in the last line requires an argument. But this (with colon added to a parameter in function declaration) runs:

f: func[:f][ print f ]
f print

and prints "print" - name of the function.

So this is an example where we control evaluation of function parameters. But this works only for a single word parameters as I understand. In other words one can not write an alternative if that would require no [] for its body using this technique, because the body will have variable length.

What I like about Rebol the most is its ambitious mood.


Rebol 3 Motivation

There's Rebol inspired Red programming language