About this ‘A Language a Day’ Advent Calendar
This series of publications transformed into my book ‘A Language a Day’, which you can get in both electronic and paper format. Languages covered in the book: C++, Clojure, Crystal, D, Dart, Elixir, Factor, Go, Hack, Hy, Io, Julia, Kotlin, Lua, Mercury, Nim, OCaml, Raku, Rust, Scala, and TypeScript.
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 colon. 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 if
—else
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:
- Red Programming Language Documentation
- What is the Red Programming Language?
- Learn Red – Fundamentals of Red (book)
- Red/System Language Specification
The source codes for today’s article are located on GitHub.
Next: Day 20. Mercury