Introduction and overview | Principles | Features | Example code | Final remarks

An appreciation of REBOL

Introduction and overview

REBOL (see website) is a programming language which combines a vast array of features with a simple syntax for representing instructions as well as data. As a functional language, its basic operation is the application of a function to arguments. All control structures are actually functions on blocks of data interpreted as code and new control structures can be easily provided by the user. There are no keywords, in the sense that all built-in functions can be redefined by the user. Furthermore, the language is reflective to a high degree: all program elements can be manipulated as data, and functions and objects can be interrogated as to their definition. As a consequence of its design, REBOL is capable of being interpreted very efficiently, and it has full run-time facilities for type-checking and error-handling. REBOL implementations exist for a great many platforms. Completely platform independent facilities for Graphical User Interface construction exist in several major versions, each built on the lower-level facilities built into the language.

It could be said that REBOL is based on two main ideas: “do not make distinctions unless needed”, and “do the obvious things simply”. Thus there is no distinction in REBOL between

  • programs and data
  • identifiers (variables) and values
  • values and functions
  • functions and operators (except that of prefix/infix notation)
  • functions and control constructs
  • types and values

Most functions and control constructs have a basic form, which represents the most obvious functionality, and “refinements” (cf. switches/options) for expressing additional or specialized functionality. Construction and conversions functions for values of the various types usually operate in a very intuitive way.

Principles

REBOL’s programming paradigm is functional, i.e. the operation of a program consists of the evaluation of expressions, each of which (if not consisting in a literal value) is the application of a function to arguments . This application is generally not free of side-effects – on the contrary, side-effects are an important component of REBOL’s semantics.

The language has a deceptively simple syntactic structure: a program is a sequence of typed expressions, where every expression is either a literal, or a – possibly empty – sequence of expressions, enclosed in either parentheses ( ) or square brackets [ ]; the latter construct is called a block. The lexical and syntactic analysis phase of the REBOL interpreter is mainly concerned with recognizing literal values and checking proper nesting of parentheses and brackets. There are no variables as such, and identifiers are just literal values of a certain type (word), with the property that they can be bound to other values. Even operators are bound words.

One of REBOL’s assets is the large repertoire of built-in value types and corresponding literal forms. These types are by-and-large problem-oriented, although some implementation-related types are also provided. There are no “composite types”, i.e. no type constructors, but many types have composite values and there are convenient mechanisms to access the components.

The evaluation rules of REBOL are likewise deceptively simple: a literal other than a word evaluates to itself, a word evaluates to the value it has been bound to, if any (this may be an operator or function); functions normally evaluate their arguments before being applied, but their specification can state that the argument is not to be evaluated before being passed; operators always evaluate their left and right operand and are greedy, i.e. evaluation of operand-operator-operand expressions takes precedence over function application; also, operator evaluation is strictly from left to right and there is no operator precedence, but parentheses may be used to control the evaluation order.

The value of an evaluated sequence of expressions (whether enclosed in parentheses or square brackets) is the value of the last expression evaluated in it, or the special value unset if the sequence was empty. A parenthesized sequence of expressions is automatically evaluated unless it is argument to a function which inhibits evaluation; a block is not evaluated unless it is argument to a function that evaluates it explicitly.

The attempt to evaluate a word may result in one of three outcomes: it has not been bound, it has been bound but not set, or it has been bound and set (possibly to the special value none).

Features

REBOL has no keywords: a great many built-in operators and functions are bound to certain words at program start, but these words may be freely redefined. Control constructs (if, case, while, for, …) are functions like any other. Quite a few such constructs are provided as built-in functions, but new ones may be freely defined.

The language is homo-iconic i.e. a program (fragment) is indistinguishable from data and can be manipulated by program. Admittedly, this makes attacks by code injection a real possibility, but security facilities exist to minimize the risk. Furthermore REBOL has strong reflective features: many system properties including identifier bindings (contexts) are accessible as normal data from within the program; this goes also for most properties of values, such as their type and size, the names of the components of composite types and the argument names and types of functions and operators. These features are also of considerable value in producing accurate documentation, including help facilities.

A large number of construction and conversion functions exist to make values of the various types and to transform values of one type into those of another.

A salient feature of the language is its full support for recursive-descent parsing with semantic actions. This allows the user to freely define and process dialects or domain-specific languages (DSLs), e.g. business rules, within the language. The language itself already defines several such dialects, amongst others for the specification of the parsing rules themselves, for the specification of function arguments and for the arguments to construction functions for values of composite types such as bitsets, and objects. The specification of windows and controls for the Graphical User Interface also uses dialects extensively.

One of REBOL’s strengths is its concept of series as the unification of a large number of different types representing ordered collections of values, combined with a rich repertoire of functions applicable to series values and in many cases also to values of related types. Series instances are handled as referenced values for which a series pointer is maintained. Generally, more than one series pointer can exist into the same series. Operations on series include navigation, extraction and setting of sub-series and single components, set-theoretical operations, sorting and searching, and property extraction. Owing to the consistent treatment of referenced values, there is no need for explicit pointer types corresponding to each of the various series types; for low-level programming and interfacing, a generic pointer type (handle) is available.

Because every value carries its type, and the type can be determined programmatically, all functions can be polymorphic. Syntactic means are available to specify restrictions on the type of an argument by means of typesets (subsets of the defined types), and these restrictions can be checked at run-time.

The language defines a single type object through which it provides a fairly complete set of features to facilitate programming in Object Oriented style.

For input/output, high-level read and write functions operate on files and urls alike, but for more control, ports can be defined which allow both synchronous and asynchronous operation, and which are characterised by a scheme, e.g. http, dns, console, clipboard, …

For both ports and user interaction (screen, mouse, keyboard), the language provides an event handling system.

Graphics is handled by an image datatype that represents pictures with 32 bits per pixel (RGBA color space, uncompressed), combined with built-in conversion functions from and to various popular formats, as well as a basic mechanism for window creation and dialects for producing vector graphics and rich text. On top of that, REBOL itself provides a user-friendly dialect for the creation and positioning of controls and describing their interaction. Several other equivalent dialects have been developed and made available by others, on an open source basis.

Well-structured facilities for error handling are also part of the language.

Example code

The following REBOL program (script) implements the tile game which consists of shifting 15 blocks placed in a 4x4 arrangement with one free space, so as to achieve the desired ordering. It is a complete program that will execute with any copy of the REBOL/View system, freely downloadable from this page.

REBOL [] view layout [
    origin 0x0 across space 0x0
    style piece button 60x60 [
        if not find [0x60 60x0 0x-60 -60x0] face/offset - empty/offset [exit]
        temp: face/offset face/offset: empty/offset empty/offset: temp]
    piece  "1"	piece  "2"	piece  "3"	piece  "4" return
    piece  "5"	piece  "6"	piece  "7"	piece  "8" return
    piece  "9"	piece "10"	piece "11"	piece "12" return
    piece "13"	piece "14"	piece "15"	empty: piece silver ""
]

Notes:

  • The empty block following the obligatory REBOL word may contain metadata, such as the script title, version etc.
  • The block that follows the layout word is in the VID dialect, which provides convenient formulation of controls and other graphical elements. This block is argument to the layout function, which converts it to the internal representation necessary, and the result is argument to the view function which presents a window and handles the interaction.
  • Expressions like 0x0 are literals of type pair, which can be used to model sizes and positions.
  • The word style introduces the definition of a new kind of control, in this case piece, which is derived from the built-in style button.
  • The block following the 60x60 literal is the code to be executed when the button is clicked. The word face refers to the actual control. Note that the piece control is instantiated 16 times, each time with a different button text, of which once with a name (empty) assigned to it. This name is available to the code.
  • Controls are internally represented by objects, which are composite values whose components are selected through expressions like face/offset.
  • To assign a name to a value (more appropriately, to set the value of a bound identifier, i.e. value of type word) one employs an expression like temp: face/offset which does the setting and returns the set value.

The working program is downloadable from my site.

Final remarks

In my experience, REBOL is a productive tool for rapid and reliable application development.

Written by Rudolf W. MEIJER. Comments are invited by e-mail.

Introduction and overview | Principles | Features | Example code | Final remarks