Red at a Glance — A Language a Day, Advent Calendar 2019 Day 19/24

About this ‘A Language a Day’ Advent Calendar 2019

Welcome to Day 19 of this year’s A Language a Day Advent Calendar. Today’s topic is introduction to the Red programming language.

Facts about the language

Some facts about the Red programming language:

  • Based on Rebol
  • Can be used for low-level programming (via Red/System) and as a high-level language
  • Allows both imperative and functional styles
  • Offers direct GUI support
  • Appeared in 2011
  • Website: www.red-lang.org

Installing and running Red

To install Red, download one of the files corresponding to your operating system from the official website.

What you’ve just downloaded, is not an installation package but an executable file—the Red compiler. As a Mac or Linux user, set the x bit for the file and execute it. Additionally, you can move the file to a proper place:

$ chmod a+x red-064.dms
$ cp red-064.dms /usr/local/bin/red

Having this done, you can execute a program:

$ red helloworld.red

Alternatively, you can compile and execute it:

$ red -c helloworld.red
$ ./helloworld 

Hello, World! in console

Here is a terminal-oriented program:

Red []

print "Hello, World!"

The first line is the Red header, and you need it in the program. The pair of brackets are empty now, but you can add additional attributes there, for example:

Red [Title "Hello, World! program"]

print "Hello, World!"

Hello, World! with GUI

Here is another version of the Hello, World! program that creates a window and prints a message there:

Red [Needs: 'View]

view [text "Hello, World!"]

And this is how it looks like when you run it:

print and prin

An interesting fact that is worth noting is that the print function prints the value and adds a newline, while prin (with no t at the end) does not add a newline.

Words

There are no keywords in Red, but instead, programs consist of words. A word is a sequence of letters, digits, and other characters, including + - ` * ! ~ & ? |. A digit should not be the first character of a word.

Variables

To bind a word to a value, use a semicolon. No extra keywords are needed (as mentioned before, there are no keywords in Red).

Red []

name: "John"
print name

You can also get a value symmetrically to the binding, if you wish:

print :name

Precedence and execution order

Let me make a separate note on how Red deals with arithmetic expressions. You must use parentheses to force the order of the operations if it is different from a simple left-to-right execution. Compare the following two expressions:

Red []

print 10 + 20 * 30   ; 900
print 10 + (20 * 30) ; 610

Alternatively, use the math function:

print math [10 + 20 * 30] ; 610

Functions

Let us start with functions that do not take or return values. In this case, those are code blocks. You can create a block with [] and then execute it with the do word.

Red []

greet: [print "Hello, World!"]
do greet

Alternatively, you can bind a word with an executable block using the does word.

Red []

greet: does [print "Hello, World!"]
greet

Here, the second line executes it. This program says that the greet word does the given printing. Similar to variables, we bind a meaning to the word.

Whenever a function takes parameters, use func.

Red []

x2: func [x] [x * x]

print x2 5  ; 25
print x2 14 ; 196

A Factorial example

Here is a program that implements a recursive calculation of a factorial.

Red []

factorial: func [n] [
    either n < 2 [1] [n * factorial (n - 1)]
]

print factorial 1 ; 1
print factorial 5 ; 120
print factorial 7 ; 5040

This code uses the either word, which is a Red equivalent of a traditional ifelse construct.

Refinements

A refinement is something similar to optional parameters of functions in other languages. Consider the following greeting function:

Red []

greet: func [name] [
    print ["Hello" name]
]

greet "John"

Let us allow making an informal version of the function. It prints "Hello" as a default version, but changes it to "Hi" when it is called as greet/informal.

Red []

greet: func [name /informal] [
    how: either informal ["Hi"] ["Hello"]
    print [how name]
]

greet "John" ; Hello John
greet/informal "John" ; Hi John

Objects

Red implements a prototype-based object model. To create an object, use make object! or a shortened form of this construct, object:

person: object [
    name: "John"
    age: 30   
]

Notice that object! is a built-in type similar to other types such as integer! You can, for example, create a new integer like this:

answer: make integer! 42

I wonder if you can guess how to access our person’s data fields. Here is the answer:

print p/name
print p/age

It is also possible to set a new value:

person/age: 31
print person

Inheritance

Undefined values can be introduced with none, and you can use it for creating object templates. For example, the next program creates two person objects, both of which have a common company name.

Red []

person: object [
    name: none
    age: none
    company: "XYZ"
]

john: copy person
john/name: "John"
john/age: 30

alla: copy person
alla/name: "Alla"
alla/age: 31

print john
print alla

The same result can be achieved differently, by moving the common field to a separate object, and by creating a combined object for both persons:

Red []

person: object [
    name: none
    age: none
]

company: object [
    company: "XYZ"
]

john: make person company
john/name: "John"
john/age: 30

alla: make person company
alla/name: "Alla"
alla/age: 31

print john
print alla

Notice how the make is used to create an object that inherits both person and company.

A Polymorphic example

Let us utilise objects and inheritance to create an array of two animals, a dog and a cat, and call the info ‘method’ on each of them:

Red []

animal: object [
    basis: does [print "I am an animal."]
]

dog: object [
    info: does [print "I am a dog."]
]

cat: object [
    info: does [print "I am a cat."]
]

zoo: []
append zoo make animal cat
append zoo make animal dog

foreach x zoo [
    x/basis
    x/info
]

Get more

In this post, a lot of interesting topics were not covered. For example, the Red/System dialect for low-level system programming. Another example is GUI programming.

If you are used to C-like languages, Red seems an unusual language. To get it deeper, you should take granted that it is a so-called homoiconic language. This means that the program directly reflects the execution tree of it, and the program code can be considered as data. Understanding this postulate makes programming in Red easy 🙂

Refer to the following resource to learn more:

The source codes for today’s article are located on GitHub.

Next: Day 20. Mercury

Leave a Reply