REBOL

Rebol Programming For The Absolute Beginner

By: Nick Antonaccio
Updated: 4-13-08
----------------------
68 YouTube video tutorials that follow this text (10 hours of video) are available here.
A more concise version of this tutorial is available here (practical fundamentals - just the facts).
For an even shorter introduction, try this program for children (it's also suitable for adults who want a simple quick-start).

Contents:

1. For New Programmers and for New Rebolers
2. Some Perspective for Beginners
3. Using the Rebol Interpreter to Speak to the Computer - "Hello World"
3.1 Five Short Examples
4. First Code Examples - Creating a GUI Window
5. More Examples
6. A Quick Comparison
7. Understanding Variables and Functions
8. Rebol Words
9. Before You Get Too Far - Learn by Doing
10. GUI Words and Grammar - Some More Depth
10.1 Actions
11. Creating Your Own Variable Words
12. Blocks and Series
13. Function Words
14. Several Ways to Create Functions in Rebol - Passing Variables
15. Conditional Operations
16. Looping
17. Working With Longer Examples
17.1 "Compiling" Rebol Programs - Distributing Packaged .EXE Files:
18. Embedding Binary Data
18.1 Compression
19. Modular Programming and Code Reuse
19.1 Using External Programs as "Modules":
20. A Quick Summary of the Rebol Language
20.1 Using Rebol's Built-In Help
21. 8 Complete Rebol Programs For You To Study
21.1 Little Email Client
21.2 FTP Chat Room
21.3 Looping Through Data
21.4 Image Effector
21.5 Sliding Tile Game
21.6 Guitar Chord Diagram Maker
21.7 Listview Database
21.8 Peer-to-Peer Instant Messenger
22. Menus
23. More About GUIs and Graphics
23.1 Responding to Special Events in a GUI - "feel"
23.2 2D Drawing, Graphics, and Animation
23.3 Using Animated GIF Images
23.4 3D Graphics with r3D
24. Multitasking
25. DLLs and Shared Code Files
25.1 What They are and Why to Learn About Them
25.2 How To Use Them
26. Understanding the CGI Interface and Web Programming with Rebol
27. Database Concepts - Using MySQL
27.1 Setting up and using MySQL
27.2 Tables and SQL statements
27.3 Using SQL Statements in Rebol code
27.4 Putting It All Together
27.5 Short Format
28. Parsing
29. Rebol Objects
30. Common Errors
30.1 Trapping Errors
31. How to Organize Your Coding Thought - Some Real World Examples
31.1 Using Outlines and Pseudo Code
31.2 Case 1 - Scheduling Teachers
31.3 Case 2 - Downloading Directories
31.4 Case 3 - Creating a Tetris Game Clone
31.5 Case 4 - Coding a Freecell Game Clone (GUI)
31.6 Case 5 - Vegetable Gardening
31.7 Case 6 - Scheduling Teachers, Part Two
31.8 Case 7 - An Additional Teacher Automation Project
31.9 Case 8 - An Online Member Page CGI Program
31.10 Case 9 - A CGI Event Calendar
31.11 Case 10 - A Simple Image Gallery CGI Program
32. Other Topics
32.1 6 Rebol Flavors
32.2 Spread the Word: 7 Reasons to Learn and Use Rebol
33. What Next?
33.1 A Final Point
34. Feedback

1. For New Programmers and for New Rebolers

This tutorial demonstrates how easy it is to accomplish real world programming goals with a flexible and powerful language called Rebol. The text aims to teach average users to program computers to do useful things, without the long and difficult learning curve imposed by other programming languages. If you're an experienced programmer, it's strongly recommended that you read this more concise tutorial. You'll be amazed at Rebol's compact code and simple cross-platform usability. If you're a beginner, you won't find another tutorial, book, or language that enables you to accomplish more useful programming tasks within a few hundred pages. Rebol is more productive than anything else, anywhere.

A downloadable package of 11 code examples from this tutorial is available at:

http://musiclessonz.com/rebol_tutorial_examples.zip

The zip file contains screen shots and executables demonstrating what can be easily accomplished by a casual, part-time Rebol coder, within several weeks of study. Here are a few examples:

A YouTube video version of this tutorial is available at http://musiclessonz.com/rebol_video_links.html

The concepts demonstrated throughout the tutorial will help new programmers understand other languages and programming tools, and will lay the groundwork for novices to acquire essential coding skills. Even novices will be able to actually create useful Rebol programs in the first few days. And Rebol isn't limited to certain types of applications or operating systems. Code written in Rebol is able to run unchanged on over 40 operating systems, and can be used to build an enormous variety of user applications with modern graphics, CGI interfaces, network functionality, database connectivity, and much more. If you're used to other development environments, you'll find that Rebol is a beautifully designed language, contained in a dramatically small and efficient package that elegantly replaces many other mainstream tools. Learning Rebol is productive, enjoyable, and thought provoking for both new and experienced coders. No matter what your experience level, learning Rebol will save you time and frustration at some point in your programming endeavors. It's a fantastically versatile little tool for which you'll find many uses.

2. Some Perspective for Beginners

Before diving into raw mechanics, here's a fundamental perspective that's helpful to understand:

Modern computers, operating systems and programs all do very basic things, in limited ways, with a limited scope of data types:

  1. They let users input various types of data: text, images, sounds, video, etc.
  2. They let users save, retrieve, organize, share/transfer, manipulate, alter, view and otherwise deal with that data in useful ways.

Everything that can be done with a modern computer basically involves manipulating text and non-text data (non-text data is called "binary" data). In the current state of modern computing, data of all types is typically input, manipulated, and returned via graphical user interfaces such as Windows program interfaces, web forms displayed in browsers, and other keyboard/mouse driven "GUI"s. Data is saved on local hard drives and storage devices (CDs, thumb drives, etc.) and on remote web servers, and is typically transferred via local networks and Internet connections. Knowing how to control those familiar computing elements to allow users to manipulate data, is the goal of learning to program. It doesn't matter whether you're interested in writing business applications to work with inventory and scheduling (text data), programs to alter Internet web pages or emails (text and image data), programs to organize or play music (binary data), programs to transfer files across networks (text and/or binary data), programs to broadcast video and sound across the Internet (rapidly transferred sequential frames of binary data), programs to control robotic equipment, programs to play games, etc... They all require learning to input, manipulate, and return data of some sort. You can do all those things with Rebol, and once you've done it in one language, it's easier to do with other specialized languages and programming tools.

Rebol handles common user interfaces and data types easily and intuitively. It allows programmers to quickly build graphic interfaces to input and return all common types of data. It can easily manipulate text, graphics, and sounds in useful ways, and it provides simple methods to save, retrieve, and share data across all types of hardware, networks, and the Internet. That makes it a great way to begin learning how to program. For more information about the useful qualities of Rebol, see http://musiclessonz.com/rebol.html#section-1.

3. Using the Rebol Interpreter to Speak to the Computer - "Hello World"

The Rebol interpreter is a program that runs on your computer. It translates written text organized in the Rebol language syntax ("source code") to instructions the computer understands. One of the great things about Rebol is that it's a very small program, contained in a single file. There are versions that run on just about every type of computer and operating system (Windows PC, Macintosh computer, Linux web server, etc.), without any complicated install process. It lets you speak to all those machines using the same language. You just download the Rebol interpreter program, feed it a text file full of code, and the machine does what you want, with the data you want. It's easy to use and only about 1/2 meg to download (less than a minute even on a slow dialup connection).

To get the free Rebol interpreter for Microsoft Windows, go to http://rebol.com/view-platforms.html and download the view.exe file for Windows - it's clearly marked, just click it with your mouse and save it to your hard drive. When you run view.exe for the first time, you can install it if you want, but you don't have to. Just follow the instructions on screen. Once you've got the Rebol interpreter downloaded and running on your computer, click the "Console" icon, and you're ready to start typing in Rebol programs. To create your first program, type the following line into the Rebol interpreter, and then press the [Enter] (return) key on your keyboard:

alert "Hello world!"

Before going any further, give it a try. Download Rebol, and type in the code above to see how it works. It's simple and it only takes a moment. If you want to run Rebol on any other operating system, just select, download and run the correct file for your computer. It works the same way on every operating system.

3.1 Five Short Examples

To whet your appetite, here are 5 tiny GUI programs that demonstrate just how potent Rebol code is. The first example is a fully functional web page editor. You can use it to edit html pages and other text files on any web site ftp server:

view layout [
    h1 "Enter your ftp info, then click 'load' to download and edit a file:"
    p: field 600 "ftp://user:pass@website.com/public_html/filename.html"
    h: area 600x440 across 
    btn "Load" [h/text: read (to-url p/text) show h]
    btn "Save" [write (to-url p/text) h/text]
]

Here's a classic graphic sliding tile game:

view center-face layout [
    origin 0x0 space 0x0 across 
    style p 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
    ]
    p "A" p "B" p "C" p "D" return p "E" p "F" p "G" p "H" return
    p "I" p "J" p "K" p "L" return p "M" p "N" p "O"  
    empty: p 200.200.200 edge [size: 0]
]

Here's a little painting program:

view layout [
    h1 "Paint with the mouse:"
    scrn: box black 400x400 feel [
        engage: func [face action event] [
            if find [down over] action [
                append scrn/effect/draw event/offset show scrn
            ]
            if action = 'up [append scrn/effect/draw 'line]
        ]
    ] effect [draw [line]]
    btn "Save" [
        save/png %/c/painting.png to-image layout [
            origin 0x0 box black 400x400 effect pick get scrn 9
        ] alert "Saved to C:\painting.png"
    ]
    btn "Clear" [scrn/effect/draw: copy [line] show scrn]
]

Here's an even more compact version of the above program:

view layout[h1 "Paint:" s: area 700x500 feel[engage: func[f a e][
if a = 'over[append s/effect/draw e/offset show s]if a = 'up[
append s/effect/draw 'line]]]effect[draw[line]]b: btn "Save Image"[
save/png %a.png to-image s alert "Saved to 'a.png'"]btn "Clear"[
s/effect/draw: copy [line] show s]]

And just to take that example to the limit, here's the smallest painting program you'll ever see, in any programming language:

view layout[s: area feel[engage: func[f a e][if a = 'over[append 
s/effect/draw e/offset show s]]]effect[draw[line]]]

Here's a short program that uses Rebol's parsing and networking abilities to display the current WAN and LAN IP addresses of your computer:

parse read http://whatsmyip.org/ [thru <title> copy my-ip to </title>]
parse my-ip [thru "Your IP is " copy stripped-ip to end]
alert to-string rejoin ["WAN: " stripped-ip " ---- LAN: "
    read join dns:// read dns://]

Here's a little email client you can use to read and send emails to/from any pop/smtp server (edit the first line so it contains your personal email account info):

set-net [user:pass@website.com smtp.website.com pop.website.com]
view layout[
    h1 "Send:" a: field "user@website.com" s: field "Subject" b: area
    btn "Send"[
        send/subject to-email a/text b/text s/text alert "Sent"
    ]
    h1 "Read:" m: field "pop://user:pass@website.com"
    btn "Read"[editor read to-url m/text]
]

Try pasting those examples into the Rebol interpreter to see what just a little Rebol code can do (those programs take up a total of less than 1 printed page of code). Before the end of this tutorial you'll know exactly how they all work, and much more...

4. First Code Examples - Creating a GUI Window

Now for some code! Computer programs typically use Graphical User Interfaces ("GUI"s) to get data from the user and to display data to the user. GUIs work intuitively, and modern computer users are familiar with them. They contain clickable buttons, text entry fields, menus, images, and other "widgets" that allow the user to interact with the computer. Windows programs are GUIs. Web pages are also GUIs. Users click buttons with the mouse pointer to perform actions, select settings from menus, type text data into fields, etc. Most modern programming languages include some facility to build graphic interfaces that can be used to interact with the user. Rebol makes GUI creation easier than any other language. To create a simple GUI window, just type the following line into the Rebol interpreter, and press [ENTER]. Notice the "view layout" words in the examples below - you'll use them every time you create a GUI interface in Rebol:

view layout/size [] 400x300

That line of code creates a window 400 pixels across and 300 pixels down (pixels are dots on the computer screen). It doesn't do anything yet, but the GUI window can be moved around the screen, minimized and closed (with the "X" in the upper right hand corner), just like any other Windows program. In other programming languages, just creating a window like that can take several pages of code and lots of preliminary understanding. Rebol makes it easy.

To add a button to the above GUI, type the following code. Notice that the word "button" has been added between the brackets:

view layout/size [button] 400x300

Now the GUI has a generic blue button that you can click with the mouse. To add some text to the button, type the following code. Notice that the text "Click Me" has been added after the button:

view layout/size [button "Click Me"] 400x300

To make the button do something, type the following code, and then click the GUI button with your mouse pointer. Notice that the text [alert "Clicked!"] has been added after the button text:

view layout/size [button "Click Me" [alert "Clicked!"]] 400x300

Now when you click the button in your GUI, the computer responds by alerting you with the message "Clicked!". To make the program do something a bit more interactive, type the following, and then click the GUI button once again. Notice the "data: request-text" addition at the beginning of the line. That code requests some text from the user and assigns it to the word "data", so it can be referred to and used in the program:

data: request-text view layout/size [
    button "Click Me" [alert data]] 400x300

The code above is split onto two lines so that it fits within the width of this web page, but it can be typed into the Rebol interpreter as a single line. That one line is all it takes to create a program which gets some data from the user, creates a graphic user interface that waits for user interaction, and does something with the input data (displays it in a little dialog box).

Next, we'll save some data to your computer's hard drive. Type in the following code, and click "yes" if the Rebol interpreter asks for your permission to write to the hard drive. Notice the "write %/c/data.txt data" added to the end of the line. That code writes the data collected from the user, to a file on the C: drive called "data.txt"

data: request-text view layout/size [
    button "Click Me" [alert data]] 400x300 write %/c/data.txt data

If you look on your computer's C: drive after closing the GUI, you'll see that there now exists a text file (C:\data.txt) containing the text you typed into the program. (If you're working in an operating system other than Windows, you'll need to change the "c" character in the above line to refer to a root directory on your hard drive).

With that one line of code, you've got a working program that actually does something useful. It gets, displays, and saves some data from a user, using familiar GUI interactions. You could adjust it to store phone numbers, usernames/passwords, or any other useful information. It's easy - and things only get more interesting from there!

Rebol is great at dealing with all types of common data - not just text. You can easily display photos and other graphics in your GUIs, play sounds, display web pages, etc. And it's just as good at dealing with data transferred across networks and the Internet. Here's some code that downloads an image from a web server and displays it in a GUI - notice the "view layout" words again:

view layout [image load http://rebol.com/view/bay.jpg]

The word "image" inside the brackets displays a picture in the GUI. The word "load" downloads the image to be displayed.

Rebol allows many built-in effects to be applied to images. Notice the "effect [effect type]" code in the following examples:

view layout [image load http://rebol.com/view/bay.jpg effect [Grayscale]]
view layout [image load http://rebol.com/view/bay.jpg effect [Emboss]]
view layout [image load http://rebol.com/view/bay.jpg effect [Flip 1x1]]

Here's how you can read that same file from the web server and save it to your C: drive. The "/binary" modifier is used whenever reading or writing binary (non-text) data:

write/binary %/c/bay.jpg read/binary http://rebol.com/view/bay.jpg

Now you can read the image directly from your hard drive and display it in a GUI. Just type in the code below. Notice the "view layout" words again, and this time in between the brackets, the file is loaded from the local C: drive:

view layout [image load %/c/bay.jpg]

It's important to note here that you could also use that image in other graphic applications on your computer - including other programs that aren't written in Rebol. You could, for example, open that file in an image editing program, or attach it to an email and send it to a friend. It's critical to understand that data can be interoperable between languages, programming tools, operating systems, and other connected domains. As you learn more about programming, you may find specialized tools that accomplish certain programming goals easily and effectively. You can trade data between various tools by just saving it to a shared storage medium. In that way, all programming languages and tools can be used together to accomplish complex goals. That's a key concept to keep in mind when learning about general programming. Very little technology is truly new. The basis for most computing applications has been around for several decades (hard drives for storing files within directory structures, hardware for inputting and outputting text, graphic, audio, and other data, networks for transferring data between machines, etc.). Those base components haven't changed too dramatically. They've simply improved in speed and capacity - and the software tools used to work with them have evolved to allow programmers to do high level things more quickly and easily. An adept programmer writing an application to deal with large amounts of text data shared across the Internet, however, will realize that the data all still resides in files on a hard drive somewhere, in a machine connected to a network, and that data can be accessed by various old fashioned programming means - even if it was created and put there by a program using cutting edge database technology, displayed in a flashy new graphic interface, and transferred over broadband wireless connections. It's still just text data saved in a file somewhere, and it can be manipulated via virtually any language that provides access to networks and text files! Keep that in mind as your exposure to various programming tools expands...

5. More Examples

Below are some more short examples of reading, writing, and manipulating data on the hard drive and Internet, and interacting with the user. Type them into the Rebol interpreter to familiarize yourself with a bit more of the Rebol language.

Before going on, you may want to configure Rebol to open straight to the interpreter console. Click the "User" menu on the Rebol Viewtop, and uncheck "Open Desktop On Startup". That'll save you the trouble of clicking the "Console" button every time you start Rebol.

The following line displays the current day and time in the interpreter:

print now

The word "print" displays text data directly in the Rebol interpreter. The word "now" refers to the current date and time.

The following line performs some mathematical computations, and displays the result:

print (10 + 12) / 2

The following code asks the user to choose a file on the hard drive:

request-file

The code below allows the user to choose a color:

request-color

The following code asks the user a yes-no question:

request "Are you having fun yet?"

Here's a nice way to let the user select a date:

request-date

The code below requests a username and password from the user:

request-pass

The following code opens your computer's web browser and displays the indicated web page:

browse http://rebol.com

The following code launches Rebol's built in text editor, and opens the file c:\test.txt

editor %/c/test.txt

Notice the percent character ("%") in the example above. In Rebol, that character is used to represent all file labels. Because Rebol can be used on many operating systems, and because those operating systems all use different syntax formats to refer to drives, paths, etc., Rebol uses the universal format: %/drive/path/path/.../file.ext . For example, "%/c/windows/notepad.exe" refers to "C:\Windows\Notepad.exe" in Windows. Rebol converts that syntax to the appropriate operating system format, so that your code can be written once and used on every operating system, without alteration.

The following line sends an email to user@website.com, containing the text "Hi user. How are you doing?". Try replacing the username and website with your own email address (If you downloaded and ran Rebol without actually installing it, you'll need to run the configuration wizard in order to send the email. To do that, type "install" and follow the instructions.):

send user@website.com "Hi user.  How are you doing?"

The line below sends a web page to user:

send user@website.com read http://www.rebol.com

The code below displays the contents of user's email inbox:

print read pop://user:pass@website.com

The following line uploads a single file to user's web server using ftp:

write/binary ftp://user:pass@website.com read/binary %file

The following uploads an entire directory of files to user's web server:

foreach file load %./ [if not dir? file [write/binary join
    ftp://user:pass@website.com/ file read/binary file]]

It all looks a lot like spoken English, doesn't it? You just need to type things in correctly, and the computer does what you want. The more of the language you learn, the more you'll be able to make the computer do your bidding... Easy, right?

6. A Quick Comparison

To provide a quick idea of how much easier Rebol is than other languages, here's a short example. The simplest code to create a basic Rebol GUI window was presented earlier:

view layout/size [] 400x300

It works on every type of computer, in exactly the same way.

Code for the same simple example is presented below in the popular programming language "C++". It does the exact same thing as the Rebol one-liner above, except it only works in Microsoft Windows. If you want to do the same thing on a Macintosh computer, you need to memorize a completely different page of C++ code. The same is true for Unix, Linux, Beos, or any other operating system. You have to learn enormous chunks of code to do very simple things, and those chunks of code are different for every type of computer. Furthermore, you typically need to spend a semester's worth of time learning very basic things about coding format and fundamentals about how a computer thinks before you even begin to tackle useful basics like the code below:

#include <windows.h>

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "C_Example";

int WINAPI
WinMain (HINSTANCE hThisInstance,
         HINSTANCE hPrevInstance,
         LPSTR lpszArgument,
         int nFunsterStil)

{
    HWND hwnd;               
    /* This is the handle for our window */
    MSG messages;            
    /* Here messages to the application are saved */
    WNDCLASSEX wincl;        
    /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      
    /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 
    /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 
    /* No menu */
    wincl.cbClsExtra = 0;                      
    /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      
    /* structure or the window instance */
    /* Use Windows's default color as window background */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register window class. If it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   
            /* Extended possibilites for variation */
           szClassName,         
            /* Classname */
           "C_Example",       
            /* Title Text */
           WS_OVERLAPPEDWINDOW, 
            /* default window */
           CW_USEDEFAULT,       
            /* Windows decides the position */
           CW_USEDEFAULT,       
            /* where the window ends up on the screen */
           400,                 
            /* The programs width */
           300,                 
            /* and height in pixels */
           HWND_DESKTOP,        
            /* The window is a child-window to desktop */
           NULL,                
            /* No menu */
           hThisInstance,       
            /* Program Instance handler */
           NULL                
            /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nFunsterStil);

    /* Run the message loop. 
        It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages 
            into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - 
        The value that PostQuitMessage() gave */
    return messages.wParam;
}
/*  This function is called by the Windows 
        function DispatchMessage()  */

LRESULT CALLBACK
WindowProcedure (HWND hwnd, UINT message, 
    WPARAM wParam, LPARAM lParam)
{
    switch (message)                  
    /* handle the messages */
    {
        case WM_DESTROY:
            PostQuitMessage (0);       
                /* send a WM_QUIT to the message queue */
            break;
        default:                      
            /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, 
                wParam, lParam);
    }

    return 0;
}

Yuck. Back to Rebol...

7. Understanding Variables and Functions

All programming languages make use of two important features: variables and functions. Functions are commands that tell the computer to do something. They're similar to verbs in spoken language. You've used some functions already in the earlier examples. For example, "print" is a function - it can be thought of as a verb that represents some action.

Variables are names given to data to be input, stored, manipulated, displayed, etc. They're similar to nouns in spoken language. For example, "now" can be thought of as a variable. It's a noun referring to a piece of data (the current time).

Functions and variables must be used in a syntax defined by the programming language you're using. No existing computer language allows you to speak freely as in the natural language sentence "show the user some photos of their children". You have to write the commands in a more specific way - using a syntax that invariably involves variables and functions. As a programmer, to get the computer to "show the user a photo", you'd:

  1. assign the picture filename to a variable (noun)
  2. use a function (verb) to display the image referred to by the variable
  3. assign the function action to a button or some other graphic widget in a GUI (which is itself created by arranging variables and functions in a specific order)

Rebol does many things in as "high level" a way as can be expected - as close to speaking to the computer in human English as is currently possible, but it still requires specific syntax and structure. All contemporary computer languages do. If you want to learn how to program in any language, you'll need to learn how to use variables and functions in the grammar the language defines. That's at the core of all programming.

In Rebol, variables and functions are assigned to "words".

8. Rebol Words

If you want to give a label to some data - so that it can be used in your program - you must assign it a word. The same is true for actions performed by functions. There are many function words built into Rebol that represent common actions ("print", "alert", "request-date", etc). You've seen a number of those built-in words already in the earlier examples. To create your own functions, you take previously created function words and variables, group them together in a specific order that accomplishes what you want, and assign a word to that collection of code. Then you can refer to that group of actions and/or related data, using the word you've assigned to it.

Learning the function words that are already defined in a programming language is a big part of learning to program. Those words are the existing vocabulary of the language, and in order to work correctly, they typically expect some other words to follow afterwards, in a specific order and format. The word "write", for example, writes data to a storage device (hard drive, flash drive, web server, etc). It's a function that performs an action, and expects the name of a file to be written to the hard drive, and then the name of the data to write to that file. It's gotta be written in that order:

write %/c/text.txt "This is some random text"

If you type the above line in the wrong order, it won't work:

write "This is some random text" %/c/text.txt ; WRONG

If you type it in backwards, Rebol won't understand the syntax, and you'll receive an error.

9. Before You Get Too Far - Learn by Doing

To learn any programming language, you'll need to type in lots of code, by rote. Be sure to manually key in the examples in this tutorial, not just to see them work, but to get used to speaking the language. Avoid copying and pasting if you really want to learn. At first, you'll learn to code in the same way you'd learn a new spoken language - by immersing yourself in the words and phrases of the language (even if at first you don't understand what's being said). Repeating sentences by rote is a natural way to get a feel for how a language sounds and works. Certain words, phrases and patterns eventually become familiar, and the language syntax becomes clear and more intuitive.

Seeing the examples run is absolutely essential. It helps form associations between things the computer does, and chunks of code that make those things occur. Just reading through the code isn't enough - seeing how it executes is the key. If you don't have time to manually type in code, at very least paste it into the interpreter.

Because programming languages require more specific syntax than spoken languages, learning the exact grammar is more important than in spoken language. Simple examples like the ones that follow are easy to remember - just like simple phrases memorized in spoken foreign languages. To become more fluent, however, the correct order of words, characters and other elements must be typed in exactly, in a much more specific way than components of spoken language. The interpreter is not intelligent enough to "guess" what you intend to do, and if you get the grammar wrong (even one character), it'll interpret your code incorrectly and do something different then you want. Sometimes, you'll get an error, and the interpreter will tell you where you got the grammar wrong in your code. Sometimes your program just won't work correctly. Getting intimately familiar with the syntax, from the beginning, will help you avoid those problems.

10. GUI Words and Grammar - Some More Depth

As you saw in the earlier examples, the words "view layout", followed by two brackets ("[]") can be used to display a Graphic User Interface in Rebol. You can put elements that you want to see in the GUI, inside the brackets. Rebol contains words that display all the common graphic elements used in GUIs. Try typing in the following code examples:

view layout [button]

view layout [field]

view layout [text "Rebol is really pretty easy to program"]

view layout [text-list]

view layout [
    button
    field
    text "Rebol is really pretty easy to program"
    text-list
    check
]

Notice that the words can be separated by "white space" inside the brackets. Extra spaces, carriage returns, and other empty characters are ignored by the interpreter. Tab stops are traditionally used to indent the lines within brackets, but they're not required.

More descriptive characteristics about the graphic elements can be included directly after each of their respective words. Such modifiers are called "facets" in Rebol, and they allow you to adjust all characteristics of every type of graphic widget (size, color, displayed text), etc. Try typing in the code below - it's the same as the above code, with some additional facet characteristics:

view layout [
    button red "Click Me"
    field "Enter some text here"
    text "Rebol is really pretty easy to program" purple
    text-list 400x300 "line 1" "line 2" "another line"
    check yellow
]

10.1 Actions

IMPORTANT: If you want a graphic element to perform an action, just put the action word(s) in brackets after it. When the GUI element is clicked with the mouse or otherwise activated, the action will be performed. Type in the following code to see how it works:

view layout [button [alert "You clicked the button."] ]

view layout [button red "Click Me" [alert "You clicked the red button."]]

view layout [
    text "Some action examples.  Try using each widget:"
    button red "Click Me" [alert "You clicked the red button."]
    field 400 "Type some text here, then press [Enter] on your keyboard."
        [alert value]
    text-list 400x300 "Select this line" "Then this line" "Now this line"
        [alert value]
    check yellow [alert "You clicked the yellow check box."]
    button "Quit" [quit]    
]

Notice how the word "value" refers to the selected item in the text-list, and to the text contained in the text input field.

Alternate actions (i.e., those triggered by a right click of the mouse) can be included for any graphic widget. Just enclose them in a second block, surrounded by brackets:

view layout [button [alert "left click"] [alert "right click"]]

Here are some other GUI elements used in the Rebol language:

view layout [
    backcolor white
    h1 "More GUI Examples:"
    box red 500x2
    bar: progress
    slider 200x16 [bar/data: value show bar]
    area "Type here"
    drop-down
    across 
    toggle "Click" "Here" [print value]
    rotary "Click" "Again" "And Again" [print value]
    choice "Choose" "Item 1" "Item 2" "Item 3" [print value]
    radio radio radio
    led
    arrow
    return
    text "Normal"
    text "Bold" bold
    text "Italic" italic
    text "Underline" underline
    text "Bold italic underline" bold italic underline
    text "Serif style text" font-name font-serif
    text "Spaced text" font [space: 5x0]
    return
    h1 "Heading 1"
    h2 "Heading 2"
    h3 "Heading 3"
    h4 "Heading 4"
    tt "Typewriter text"
    code "Code text"
    below
    text "Big" font-size 32
    title "Centered title" 200
    across
    vtext "Normal"
    vtext "Bold" bold
    vtext "Italic" italic
    vtext "Underline" underline
    vtext "Bold italic underline" bold italic underline
    vtext "Serif style text" font-name font-serif
    vtext "Spaced text" font [space: 5x0]
    return
    vh1 "Video Heading 1"
    vh2 "Video Heading 2"
    vh3 "Video Heading 3"
    vh4 "Video Heading 3"
    label "Label"
    below
    vtext "Big" font-size 32
    banner "Banner" 200
]

The examples above demonstrate how Rebol creates GUIs that can be used to input and display data in a variety of ways that are familiar to users. They can be customized using facets, and they can perform actions. That's a big part of building a typical modern computer program! For more information about GUI design, see http://rebol.com/docs/easy-vid.html and http://rebol.com/docs/view-guide.html. To make your GUIs do useful things, you need to learn more about making the language manipulate data in useful ways...

11. Creating Your Own Variable Words

Just like spoken languages, programming languages are malleable and expressive. There's never only one way to write a given program. You need to choose and use your own words, and you need to organize them so they have the meaning and function you intend. Just like in spoken language, you have to think about what you're trying to say, and organize your thought process to say it. In Rebol you have the additional benefit of being able to create your own language words to express actions and to label data.

Words are created and assigned to variables and functions in Rebol by the use of the colon (":") character. You can use any word you want to refer to any specific data or action(s). For example, If you want to use the word "picture" to refer to an image file on the Internet, you could do the following:

picture: load http://rebol.com/view/bay.jpg

The above line creates a variable (label) that can be used in your program anywhere you want to read and use the file located at http://rebol.com/view/bay.jpg . The built-in Rebol word "load" does the actual work of going out to the web site address and collecting the image data.

Now you can use the word "picture" to refer to the above image. Display it in a GUI using the following code:

view layout [image picture]

The words "view", "layout", and "image" are built into Rebol, and the word "picture" is now just as valid, because it's been defined to the interpreter.

Because the word "picture" is _variable_, you can also redefine and _change_ the data referred to by it:

picture: load http://rebol.com/view/demos/palms.jpg

Now, when you use the word "picture" in your program, it refers to a different file at a different Internet location. Writing the same GUI code now displays that different photo:

view layout [image picture]

You can also make the word "picture" refer to a file on your hard drive, or anywhere else you'd like:

picture: load %/c/bay.jpg

Here are some more examples of creating and using variable words. Type them into the Rebol interpreter to see how they work, and to understand how assigned words can take the place of _any_ data. NOTE: anything after a semicolon in Rebol code is ignored by the interpreter. It's used to include human readable comments in the code. You don't need to type any of the comments into the interpreter:

acolor: "blue"

alert acolor ; alerts you with a dialog box displaying the text "blue"

print acolor ; prints the word "blue" in the Rebol interpreter

anumber: 12

print anumber ; prints the number 12 in the interpreter

computation: (10 + 12) / 2

print computation ; prints the answer

filename: request-file

print filename ; prints the name of the user chosen file

chosen-color: request-color

print chosen-color

answer: request "Are you having fun yet?"

print answer

pick-a-date: request-date

print pick-a-date

userpass: request-pass

print userpass

webpage: http://rebol.com

browse webpage

file: %./test.txt

editor file 
; launches Rebol's built in text editor and opens the filename 
; assigned above

email-address: user@webpage.com

message:  "Hi Luke.  How are you doing?"

send email-address message

The key is to be aware of the colon character (":"). It's the thing that tells Rebol to create a new variable word and assign it to some value that'll be used later.

12. Blocks and Series

In Rebol, you can use words to represent multiple pieces of data grouped together, collections of other word variables, and other programming elements. Just surround the data in brackets. Type in the code below to see how it works:

somecolors: ["red" "yellow" "blue" "black"]
; "somecolors" is now a defined word used to represent the entire 
; data block enclosed in brackets.
print somecolors

In Rebol, collections like this are called "blocks", and they're very important. In fact, they're the primary organizational unit in Rebol and the main structure in which data is stored in the language. That's very important - remember, programming is all about inputting, storing, retrieving and otherwise manipulating data. In Rebol, ANY type of data can be assigned a word, and blocks can contain any combination of words and raw data. Blocks provide a simple way of managing every conceivable type of data, and that's at the heart of all programming. Learning to work with blocks is therefore a fundamental part of learning Rebol.

You've already used blocks - brackets were snuck in earlier to display GUI elements and to perform actions on them. Any group of words surrounded by brackets forms a block, and you can assign a word to refer to that block. Words referring to complex blocks of data can be likewise grouped together into other blocks simply by surrounding the words with brackets. This makes dealing with very complex and useful data structures very easy in Rebol.

Type in the code below to see how an entire GUI layout can be built and represented by using one word label:

gui-layout: [button field text-list]

"gui-layout" now refers to that entire block of code. You can display it using the standard "view layout" syntax:

view layout gui-layout

Blocks of data can also be spread out over several lines, and can be separated by extra white space. Just surround the elements with brackets:

gui-layout2: [
    button red "Click Me"
    field "Enter some text here."
    text "Rebol is really pretty easy to program." purple
    text-list 400x300 "line 1" "line 2" "another line"
    check yellow
]

Now display it in a GUI:

view layout gui-layout2

Layout blocks much bigger than that can be stored in a single word!

NOTE: It's standard practice to indent compound blocks with consecutive tab stops. Starting and ending brackets are typically placed at the same indentation level. This is conventional in most programming languages, because it makes complex code easier to read. For example, the compound block below:

[blue red green [1 2 4 [jan feb march [monday tuesday wednesday]]]]

can be written a bit more clearly as:

[blue red green 
    [1 2 4 
        [jan feb march
            [monday tuesday wednesday]
        ]
    ]
]

Indentation is not required, but it's very helpful when dealing with more intricate programming structures.

Here's a simple data table example, containing schedule information within a block:

schedule: [
    ["John Smith" "Monday" "3:00 pm"]
    ["Dave Jones" "Tuesday" "11:00 am"]
    ["Janet Duffy" "Wednesday" "4:45 pm"]
]

You can display the above block in a GUI, using the built-in Rebol word "list". Notice the "data schedule" code in the last line below - it inserts the entire schedule block defined above as data to be displayed in the list widget (the line "across text 150 text 150 text 100" is just syntax expected by the list widget to define its graphic layout):

view layout [
    vh2 "This Week's Appointments:"
    list 600x400 [
        across text 150 text 150 text 100
    ] data schedule
]

The beginnings of a graphical database application, in several lines of code... Not tough at all!

Using blocks to store collections of data is similar to using variable words to store single values. Once a word is assigned to represent a block of data, that word can be used in place of the actual data, to represent it in code. Blocks are simply able to respresent larger collections/varieties of data. You don't have to worry about how the computer stores or works with the data in memory. You can simply label the data and use it in it's natural human-understandable form, using a single consistent bracket syntax to deliniate each group of values. That's very powerful, and it's much easier than in other programming languages. In most other languages, formatting and using data in code requires quiet a bit more preparation, management, and a variety of code structures to handle different types of data.

Many of Rebol's built in words help you manipulate data stored in blocks. Type in the following code to see how the "sort" word works:

somecolors: ["red" "yellow" "blue" "black"] 

sortedcolors: sort somecolors

"Sort" is a built in function word that alphabetically (/ordinally) sorts the elements of a given block. The line above creates the newly defined word "sortedcolors", and assigns it to the sorted block of words contained in "somecolors".

print sortedcolors 
; This code displays the sorted block of text. 

print first sortedcolors 
; "first" is another built-in word.  
; It selects the first item in a given block.

find somecolors "red" 
; "find" is a built in word that searches for data within a block.

You can easily save blocks of data to your hard drive, read them from a web server, and perform other file operations with them.

write %/c/colors.txt somecolors 
; writes the entire block of text represented by "somecolors" 
; to a text file called colors.txt on the C: drive.

Here's an interesting twist, demonstrating how Rebol can easily mix datatypes within a block:

an-image: load http://rebol.com/view/bay.jpg
; downloads an image from the Internet and assigns the 
; word "an-image" to it.

append sortedcolors an-image 
; "append" adds the downloaded image to the end of the data block 
; currently containing the simple text words defined above.  
; Now the block contains both text and binary image data, 
; all assigned to a single word - not a problem in Rebol!

Now you can select items from that new block:

print first sortedcolors 
; prints the first item in the data block - the text "black".

view layout [image fifth sortedcolors] 
; displays the fifth item in the data block - 
; the image downloaded above - in a simple GUI.

That should get you thinking a bit. You can store images, sounds, text, complex data structures, and anything else you want in a block, all with equal ease. That's a complex ability which requires some hard core learning in most programming languages.

Here's some more notation to be familiar with when working with sequential data in blocks. That type of data is called a "series" in Rebol. All blocks of data are actually series in Rebol, and can be treated as sequential lists by default:

view layout [image sortedcolors/5] 
; "sortedcolors/5" is another way to refer to the fifth item 
; in a data block.

The following example puts the above notation to work in a useful way:

length-of-block: length? sortedcolors 
; the built in word "length?" returns the number of items 
; in the block (5 in this case).

view layout compose [image sortedcolors/(length-of-block)]

The word "compose" allows variables in parentheses to be evaluated and inserted as if they'd been typed explicitly into the code of the program. In the example above, the code reads as if sortedcolors/5 had been typed in manually. Another way to use variable values explicity is with the format below:

view layout [image sortedcolors/:length-of-block]

The colon symbol in front of a variable does the exact same thing as the compose function and parentheses above. You'll see both formats in Rebol code, so it's good to know both.

The following examples demonstrate additional words used to traverse sequential series of data within blocks:

insert sortedcolors "mauve" 
; adds the word "mauve" to the sortedcolors block of data.

remove sortedcolors
; removes the first item from the block.

head sortedcolors 
; sets a position marker at the beginning of the data block

next sortedcolors 
; sets a position marker at the next item in the data block

last sortedcolors 
; sets a position marker at the last item in the data block

back sortedcolors 
; sets a position marker at the previous item in the data block

tail sortedcolors 
; sets a position marker after the last item in the data block

The fact that you can mix together all types of data within a block, refer to parts of blocks by name, and access/alter data within them using built-in functions, is very powerful and useful. Blocks and variable words assigned to blocks help you store, manipulate, and refer to all the data you'll deal with in your programs. Doing so is similar to assigning nouns to groups of people, places, and things in spoken language. Within those groups, smaller groups and individual items can be named, ordered and otherwise organized - in the same way that complex database applications allow you to store and work with all types of information. The possibilities of dealing with data in that way are endless.

13. Function Words

It's easy to define your own function words (actions), once you know some of the built-in vocabulary of Rebol. Creating new functions is comparable to creating your own verb words in a spoken language. Just be careful not to unintentionally use words that are already defined in the Rebol language, or in your current program. That would change the meaning of the existing word. For example, you could accidentally change the meaning of the word "write" to refer to a picture on your hard drive by typing the following:

write: read %/c/bay.jpg   
; *** DON'T TYPE THAT IN - it'll change the meaning of the word 
; "write" in the Rebol interpreter (only for the current session).  
; It's an example of what not to do. ***

You can protect all of the built-in Rebol words by typing in "protect-system". That'll alert you with an error and disallow any attempt to redefine native Rebol words. You still must be careful not to accidentally redefine words that you've created. Word definitions only last for the current session, so if you make a mess, all you need to do is restart the Rebol interpreter.

Here's a really important concept: (drum role) ... In Rebol, you can use single words to represent entire blocks of actions (i.e., collections of function words grouped together). In fact, blocks like that form the primary code sections that make up programs in the Rebol language. Here's an example of several function words grouped together into a block (i.e., enclosed in brackets), and assigned a new function word:

some-actions: [
    alert "Here is one action." 
    print "Here's a second action."
    write %/c/anotheraction.txt "Here's a third action."
]

The above code has created a kind of super-verb that refers to several actions. You can perform the actions contained in any block using the "do" function word. To perform all the actions in the above code block, just type:

do some-actions

You can also include the word "does" right inside a word definition - that'll make the actions (function words) contained in the block perform automatically every time the new word is used in Rebol:

more-actions: does [
    alert "4" 
    alert "5"
    alert "6"
]

In fact, by including the "does" command right in the word definition, you've just created a new function (or "subroutine") that can be used like any other built-in action word in Rebol! You can now talk to the interpreter using that word, and it understands what you mean for it to do. After you've entered the code above, try typing the word "more-actions" into the Rebol interpreter:

more-actions

It's taken on a life of its own! As with variable words, the key is to be aware of the colon character - that's the symbol that actually creates the new function word.

Here's an example of a useful little action word to clear the command line screen in the Rebol interpreter.

cls: does [prin "^(1B)[J"]

The native way to clear the Rebol interpreter's command screen is by typing "prin "^(1B)[J". That's kind of awkward to type, and even tougher to remember. Instead, we can assign the word "cls" to perform the action - just like in old Basic languages. Now just type:

cls

and the screen clears - that's much easier.

Here's a little program that creates the new action word "send-email". It provides a simple text requestor interface for users to send email:

send-email: does [
    email-address: to-email request-text/title/default 
        "Enter an email address:" "user@webpage.com"
        ; the above line creates the new variable word "email-address"
        ; "email-address" is assigned the value of the 
        ; text input using the built in word "request-text"
        ; the "title" and "default" refinements customize the 
        ; info displayed in the text requestor.
    message: request-text
        ; the above line creates the new variable word "message" 
        ; and assigns it to some requested text
    send email-address message
        ; the above line sends the user-provided message to the 
        ; email address given earlier
    alert "Your message has been sent."
]

send-email ; do the routine above
send-email ; do it again to send another message to someone else

The above process is VERY important. It's the basis of how you perform more complex and useful actions in Rebol. Blocks of actions and blocks of data form the basis of how you program in Rebol. And performing actions upon data is what you'll do to complete all your programming tasks. In Rebol you just group bits of data together into blocks, and assign a name to refer to it. You also group functions together into blocks to perform actions upon the data, and assign a name to refer to those actions. You can even combine complete groups of data and functions into blocks that can be assigned unique word identifiers that perform complete programmatic tasks for you: store and manipulate data all with a single word that you define! That allows you to create your own unique language in any program you write, using words that you define. You could create, for example, your own language that reads something like "email tom at noon with the main news page from yahoo.com". Those words aren't built into Rebol, but they can be assigned the appropriate action and data meanings to make that sentence a completely functional piece of code that the computer understands! (It would still need to be syntactically correct and exact). Building word meanings in that way is called building a "dialect" in Rebol, and it's one of the ways Rebol is different from other languages. You could conceivably write a dialect for programming robotic devices that reads "Vacuum the floor. Move in concentric circles around the perimeter". You could write a dialect for doctors that reads "print prescription for John Smith" (Ponder for a moment the possibilities for that type of natural language capability and flexibility...). Translating the existing Rebol language to any other language is as simple as assigning built-in function/data words to words in the desired language (for example, translating the print function to French, Italian, and Spanish is as simple as typing "imprime: stampa: impresion: :print"). Other languages focus on different ways of grouping and managing functions and variables. Typically, other languages use more cryptic ways of doing things. For example, blocks that contain both fully encapsulated functions and variables are called "objects". You'll see more about "object-oriented" programming as you study Rebol and other languages in depth...

14. Several Ways to Create Functions in Rebol - Passing Variables

There are several built-in words in the Rebol language that allow you to create more complex function words. To create simple functions, you can use the "does" command, as described above. But some functions are more complicated than that. They perform work upon _variable_ data. For example, the following simple function displays the square root of 4. That's all it can do:

sqr-four:  does [print square-root 4]

This type of function is similar to what you saw in the previous section. The word "sqr-four" is now assigned to the action "print square-root 4" (the word "square-root" is built into Rebol). After entering the above line in the Rebol interpreter, type:

sqr-four

It'll give you the expected result of 2.

Say now, however, that you now want to do something using numbers other than 4... What if you want to create a function that adds 4 to some other number, and then computes the square root of that sum? For that to work, the other number must be changeable, and therefore must be assigned a variable name. That variable name can then be "passed" to the function. The built in word "func" is used to create functions to which changeable variables can be passed. The syntax for the word "func" expects it to be followed by two blocks of code. The first block contains the name(s) of the variables to be passed. The second block contains the actions to be taken. Here's how it looks:

func [names of variables to be passed] [
    actions to be taken with those variables
]

In the following line, a function is created in which a variable word "anumber" is named and passed. That whole function is assigned the word "sqr-var":

sqr-var: func [anumber] [print square-root (4 + anumber)]

Now you can use the word "sqr-var", and the Rebol interpreter knows what to do with the assigned data. Try the following code:

sqr-var 12 ; prints "4", the square root of 12+4 (16)
sqr-var 96 ; prints "10", the square root of 96+4 (100)

Printing the square root of 4+somenumber may not sound so exciting to you, but it helped to illustrate one of the most important techniques employed in all modern programming languages. The process of passing variable parameters to functions is a fundamental part of all modern programming. It's perhaps the single most common element in contemporary languages, and understanding how it's done is absolutely essential. Below are some more interesting real-world examples.

The following line creates a simple function to display images:

display: func [filename] [view layout [image load filename]]

It accepts an image filename as the passed parameter (%somefile.jpg, %somefile.gif, %somefile.png, or %somefile.bmp), and then creates a GUI to display the image. That set of actions is assigned to the word "display". Simple, right? Now you can use the word "display" like this:

image1: to-file request-file/title trim {
    Select an image from your hard drive:} ""
; gets an image filename from the user

display image1
; displays the above image using the new function word

display http://rebol.com/view/bay.jpg
; displays the image at the above url

display %/c/bay.jpg
; displays an image that was saved to the
; hard drive earlier in this tutorial

Once the word "display" is defined in your programs, you can use it as if it's a built in Rebol action word.

Here's an example that asks the user for 2 website urls, and then opens those sites in separate brower windows:

openwebsite: func [nameofwebsite] [browse nameofwebsite] 
; The line above creates a new function that passes a url 
; to the built-in Rebol word "browse", to open the passed 
; web site name in the user's default browser.  It also 
; assigns the new function word "openwebsite" to that set
; of actions.

website1: request-text/title "Enter a web site URL:"
; The line above assigns a new variable word "website1" to text 
; returned by the built-in Rebol "request-text" function.

website2: request-text/title "Enter another web site URL:"
; Gets some more text and assigns the new variable word "website2"
; to it.

openwebsite website1
; The line above uses the new "openwebsite" function word defined
; above, and passes it the "website1" variable word

openwebsite website2

; Uses the openwebsite function again, this time passing the
; website2 variable

In that example, the word "openwebsite" is assigned to a new function definition. "Website1" and "website2" are labels for variables passed to that function. Below is a variation which assigns a single word to that entire process:

display-website: does [ 
    openwebsite: func [nameofwebsite] [browse nameofwebsite] 
    website: request-text/title "Enter a web site URL:"
    openwebsite website
]

Now you can use the single word "display-website" in your programs to do that entire block of code.

display-website

Getting used to the above syntax and way of thinking is absolutely essential. Remember, dealing with all types of data is the main thing you'll do as a programmer. Passing variable data to functions that you create is the main way you'll perform actions upon data in all your programming. That's the current state of programming, and it's what you'll do in virtually every programming situation. Rebol makes it easy to deal with data, using its built in support for most common data types. Understanding how to input, manipulate, and output that data is your main objective. Using functions and variables as described above is a fundamental part of that process.

15. Conditional Operations

Programs often need to make decisions based on user input, program states, data content, etc. "If the user selects this option from a list, respond by executing this function". That's a common situation. "If a certain amount of time has passed, save data to the hard drive". Giving the computer a variety of actions to perform, based on a variety of expected conditions, is a fundamental programming technique used in all languages.

Mathematical operators such as = < > <> (equal, less-than, greater-than, not-equal) are typically used to perform conditional operations. Type in the following code to see how a conditional operation works:

if now/time > 12:00 [alert "It's after noon."]  
; now/time is a variation, or "refinement" of the built-in 
; function "now", that returns only the current time.

Here's a more complex example:

daily-calories: to-integer request-text/title {How many 
    calories have you eaten today?}
; gets some info from the user and assigns the variable word
; "daily-calories".  The built-in "to-integer" function
; helps make sure Rebol interprets that info as a number.
; The "{}" characters surrounding the title text work the 
; same way as quotes, but allow the string of text to 
; span several lines.  Very important.

if daily-calories > 2500 [alert "You need to stop eating now."]

The built-in Rebol word "either" chooses between two blocks of functions to perform, based on a conditional evaluation. Its syntax is:

either {condition} [
    block to perform if the condition is true
][
    block to perform if the condition is false
]

Here's an example:

either now/time > 8:00am [alert "It's time to get up!"] [
    alert "You can keep on sleeping."]

Here's a variation of the above example that allows you to set the wake up time:

wake-up: to-time request-text/title "What time do you want to wake up?"

either now/time > wake-up [alert "It's time to get up!"] [
    alert {You can keep on sleeping."}]

The built-in Rebol word "switch" chooses between numerous functions to perform, based on conditional evaluations. Its syntax is:

switch/default (main value) [
    (value 1) [block to execute if value 1 = main value]
    (value 2) [block to execute if value 2 = main value]
    (value 3) [block to execute if value 3 = main value]
    ; etc...
] [default block of code to execute if none of the values match]

You can compare as many values as you want against the main value, and run a block of code for each matching value. Here's an example:

favorite-day:  request-text/title "What's your favorite day of the week?"

switch/default favorite-day [
    "Monday" [alert "Monday is the worst!  Just the start of the week..."]
    "Tuesday" [alert "Tuesdays and Thursdays are both ok, I guess..."]
    "Wednesday" [alert "The hump day - the week is halfway over!"]
    "Thursday" [alert "Tuesdays and Thursdays are both ok, I guess..."]
    "Friday" [alert "Yay!  TGIF!"]
    "Saturday" [alert "Of course, the weekend!"]
    "Sunday" [alert "Of course, the weekend!"]
] [alert "You didn't type in the name of a day!"]

"Switch" gets used a lot because programs often require numerous multiple evaluation results to choose from.

Rebol includes a rich set of words and functional structures that help you evaluate conditions in all types of situations, and with all types of data. Understanding how to use them is a big part of learning the language.

16. Looping

Programs are often required to check conditions and to execute functions repeatedly. In fact, in most large applications the computer often loops through many instances of repetitive work. For example, in a reminder program, the application may need to continually check the time and date to see if the user should be reminded of a given event at the moment. In other types of programs, the computer may need to repetitively scan through collections of data, or repeatedly request/respond to user input. To handle such situations, "loop" structures provide programmatic ways to methodically repeat actions.

The built in word "forever" creates a simple repeating loop. Its syntax is:

forever [block of actions to repeat]

The following code builds a simple timer that alerts the user when one minute has passed. It uses a forever loop to continually check the time.

alarm-time: now/time + 60  
; assign a variable to the time 60 seconds from now
forever [if now/time = alarm-time [alert "60 seconds has passed" break]]

Notice the word "break" in the example above. It exits the forever loop so that the program doesn't run on forever once the alert has been displayed.

Here's a more interactive version that uses some info provided by the user. The heart of the program is still the loop at the end:

event-name: request-text/title "What do you want to be reminded of?"
; requests the name of an event from the user
seconds: to-integer request-text/title trim {
    How many seconds do you want to wait?}
; requests a number of seconds to wait
alert join "it's now " [
    now/time ", and you'll be alerted in " seconds " seconds."
]
; display a message
alarm-time: now/time + seconds
; set the alarm time
forever [
    if now/time = alarm-time [
        alert join "it's now " [
            alarm-time ", and " seconds 
            " seconds have passed.  It's time for: " event-name
            ] 
    break
    ]
] 
; the forever loop continually compares the set alarm time to
; the current time, then displays an alert when they match.

IMPORTANT: Notice the "join" word used in several of the lines above. It's syntax format is:

join {data} [block of data items]

Using that format, it joins together variables, text, blocks and other bits of data, so that they can be printed together, displayed, and otherwise manipulated to form a single piece of data. It's very useful! A variation on join is "rejoin". It takes a single block of data, and concatenates all the individual items into one piece of data. You should be familiar with this syntax too:

rejoin [item1 item2 item3 ...]

Now, back to loops. Here's a simple forever loop that displays/updates the current time in a GUI. Notice the block indentation:

view layout [
    timer: field
    button "Start" [
        forever [
            set-face timer now/time 
            wait 1
        ]
    ]
]

The above GUI contains two widgets: a text field which is assigned the variable label "timer", and a button with the word "Start" on it. The action block for the button contains a forever loop that loops 2 actions repeatedly (until the user closes the GUI): the built in word "set-face" sets the text in the "timer" field to the current time, the program waits 1 second, and then loops.

Often, the data dealt with in each repetition of a loop must change. Like most languages, Rebol includes a variety of functions and programmatic structures that allow you to loop through blocks of data and perform operations using consecutively changed values. A common looping structure in many languages is the "for" structure. It allows you to specify a starting value, an ending value, an incremental value, and a variable name to hold the current value, so that you can loop through consecutively changing values in a controlled way. Here's the basic Rebol syntax for a "for" loop:

for {variable word to hold current value} {starting value} {ending value} {incremental value} [block of code to perform, which can make use of the current variable value]

Here are some simple examples. Be sure to type them in to see how they work:

for counter 1 10 1 [print counter] 
; starts on 1 and counts to 10 by increments of 1

for counter 10 1 -1 [print counter] 
; starts on 10 and counts backwards to 1 by increments of -1

for counter 10 100 10 [print counter] 
; starts on 10 and counts to 100 by increments of 10

for counter 1 5 .5 [print counter] 
; starts on 1 and counts to 5 by increments of .5

for timer 8:00 9:00 0:05 [print timer] 
; starts at 8:00am and counts to 9:00am by increments of 5 minutes

for dimes $0.00 $1.00 $0.10 [print dimes] 
; starts at 0 cents and counts to 1 dollar by increments of a dime

for date 1-dec-2005 25-jan-2006 8 [print date] 
; starts at December 12, 2005 and counts to January 25, 2006 
; and by increments of 8 days

for alphabet #"a" #"z" 1 [prin alphabet] 
; starts at the character a and counts to z by increments of 1 letter

Notice that Rebol can easily loop through various types of data, forewords, backwards, and in partial increments, with a native understanding of those data types. It can automatically increment dates, money, time, etc. In other languages, that can be tough to do.

Also, notice the use of the "prin" word in the last example. It works like "print", except it doesn't automatically insert a carriage return (i.e., it prints each successively output character next to the previous one, instead of on separate lines).

Here's a "for" loop example that displays the first 5 file names in the current folder on your hard drive:

files: read %.  
; gets the current directory list, 
; and assigns that block of filenames to the variable "files"

for count 1 5 1 compose [print files/(count)] 
; starts printing with the 1st item in the block, 
; and counts up to the 5th item.

In the example above, "files/1" is the syntax representing the first item in the file list, "files/2" represents the second, and so on. Notice the "compose" word used in the for loop. In the example above, the first time though the loop, the code reads as if [print files/1] had been typed in manually, etc.

"Foreach" is another useful looping structure built into Rebol. It lets you easily loop through a block of data. Its syntax is formatted as follows:

foreach {variable name referring to each consecutive item in the given block} [a given block] [block of functions to be executed upon each item in the given block, using the variable name to refer to each item successively]

The example below prints the name of every file in the current directory on your hard drive:

folder: read %. 
; gets the current directory list, 
; and assigns that block of filenames to the variable "folder"

foreach file folder [print file] 
; loops through each file name contained in the "folder" block, 
; and prints each one consecutively.

The following line reads and prints each successive message in a user's email box:

foreach mail read pop://user:pass@website.com [print mail]

"While" is other useful looping structure found in most programming languages. It repeatedly performs a conditional evaluation, and then performs a block of code while the condition is true. While loops are formatted as follows:

while [condition] [
    block of functions to be executed while the condition is true
]

Here's a simple example:

x: 1  ; create an initial counter value 
while [x <= 5] [
    alert to-string x 
    x: x + 1
]

In English, that code reads "x initially equals 1. While x is less than or equal to 5, display the value of x, and add 1 to the value of x". (i.e., the program displays a count from 1 to 5)

NOTE: In Rebol, the code "x: x + 1" adds 1 to the current value of x. It's one of the most commonly used expressions in all programming, found in all sorts of looping situations. Notice also the word "to-string". It converts the number value in "x" to a text ("string") value. This is required because the "alert" word in Rebol only displays string types of data.

Here are some additional "while" loop examples:

while [not request "End the program now?"] [
    alert "Select YES to end the program."
]

In the above example "not" reverses the value of data received from the user (i.e., yes becomes no and visa versa)

alert "Please select today's date" while [request-date <> now/date] [
    alert join "Please select TODAY's date.  It's " [now/date]]

while [request-pass <> ["secret" "password"]] [
    alert "The username is 'secret' and the password is 'password'"]

The example below uses several loops to alert the user to feed the cat, every 6 hours between 8am and 8pm. It uses a for loop to increment the times to be alerted, and a forever loop to do the same thing every day, continuously. Notice the indentation:

forever [
    for timer 8:00 14:40:00 6:00 [
        if now/time = timer [
            alert join "It's now " now/time ".  Time to feed the cat."
        ]
        ; if not, continue looping until the next meal time arrives.
    ]
]

17. Working With Longer Examples

Most programs are longer than the examples shown so far in this tutorial. Below is an example of a more complex program. It allows the user to type in the Internet address of a web cam, and display streaming video from it. It displays the video images in a GUI that has several buttons used to control the size, location, and action on screen. In order to avoid typing in this program every time you run it, it can be saved as a text file. Whenever you save a Rebol program to a text file, the code must begin with the following bit of text:

REBOL []

That text tells the Rebol interpreter that the file contains a valid Rebol program. It must be included at the beginning of any saved Rebol program. You should include additional documentation about the program such as title and version info in between the brackets, but it's not required.

Type in or copy/paste the complete code source below into a text editor such as Windows Notepad. You can also use the built in Rebol text editor by typing "editor" in the Rebol interpreter. Save the text as a file called "webcam.r" on your C:\ drive.

(Note: this example includes a number of Rebol words and techniques that have not yet been discussed in the tutorial. The purpose of the example is simply to provide a longer text example that can be cut, pasted, and saved into a file. Don't worry if you can't understand the code at this point.)

Rebol [Title: "Webcam Viewer"]

; try http://www.webcam-index.com/USA/ for more webcam links.

temp-url: "http://209.165.153.2/axis-cgi/jpg/image.cgi"
while [true]  [
    webcam-url: to-url request-text/title/default trim {
        Enter the web cam URL:} temp-url
    either attempt [webcam: load webcam-url] 
        [break]
        [either request [trim {
            That webcam is not currently available.} trim {
            Try Again} "Quit"]
            [temp-url: to-string webcam-url]
            [quit]
    ] 
] 
resize-screen: func [size] [
    webcam/size: to-pair size
    window/size: (to-pair size) + 40x72
    show window
]
window: layout [
    across 
    btn "Stop" [webcam/rate: none show webcam]  
    btn "Start" [
        webcam/rate: 0 
        webcam/image: load webcam-url 
        show webcam
    ]
    rotary "320x240" "640x480" "160x120" [
        resize-screen to-pair value 
    ]
    btn" Exit" [quit] return
    webcam: image load webcam-url  320x240 
    with [
        rate: 0
        feel/engage: func [face action event][
            switch action [
            time [face/image: load webcam-url show face]
            ] 
        ] 
    ] 
]
view center-face window

Once you've saved the webcam.r program to C:\, you can run it in any one of a variety of ways:

  1. If you've already installed the Rebol interpreter in Windows, just find the C:\webcam.r file icon in your file explorer and double click it (i.e., click My Computer -> C: -> webcam.r). The Rebol interpreter automatically executes the script. By default, during Rebol's initial installation, all files with an ".r" extension are associated with the interpreter. They can be clicked and run as if they're executable programs, just like ".exe" files. This is the most common way to run Rebol scripts, and it works the same way on all major graphic operating systems.
  2. Type "do %/c/webcam.r" into the Rebol interpreter.
  3. Use the built-in editor in Rebol by typing "editor %/c/webcam.r" at the prompt. Pressing F5 in the editor will automatically run the script.
  4. Scripts can be run at the command line. In Windows, copy rebol.exe and webcam.r to the same folder (C:\), then click Start -> Run, and type "C:\rebol.exe C:\webcam.r" Those commands will start the Rebol interpreter and do the webcam.r code.
  5. At the Windows command prompt (in a Windows DOS box), type "C:\rebol.exe C:\webcam.r"
  6. Create a text file called webcam.bat, containing the text "C:\rebol.exe C:\webcam.r" . Click on the webcam.bat file in Windows, and it'll run those commands.
  7. Use a program such as XpackerX to package and distribute the program. XpackerX allows you to wrap the Rebol interpreter and webcam.r program into a single executable file that has a clickable icon, and automatically runs both files. That allows you to create a single file executable Windows program that can be distributed and run like any other application. Just click it and run...
  8. Buy the commercial "SDK" version of Rebol, which provides the best method for packaging Rebol applications.

IMPORTANT: To turn off the default security requestor that continually asks permission to read/write the hard drive, type "secure none" in the Rebol interpreter, and then run the program with "do {filename}". Running "C:\rebol.exe -s {filename}" does the same thing . The "-s" launches the Rebol interpreter without any security features turned on, making it behave like a typical Windows program.

17.1 "Compiling" Rebol Programs - Distributing Packaged .EXE Files:

Being able to save, run, and distribute your programs is important. You should become very familiar with the options above. Using the XpackerX packager is especially useful (not just for Rebol, but for other interpreted languages too). It saves your users from having to download, install, or run the Rebol interpreter. By packaging the Rebol.exe interpreter, your Rebol script(s), and any supporting data file(s) into a single executable with an icon of your choice, it works like a Rebol compiler that produces regular Windows programs that look and act just like those created by other compiled languages. To do that, you'll need to create a text file in the following format (save it as "template.xml"):

<?xml version="1.0"?>
<xpackerdefinition>
    <general>
        <!--shown in taskbar -->
        <appname>your_program_name</appname>
        <exepath>your_program_name.exe</exepath>
        <showextractioninfo>false</showextractioninfo>
        <!-- <iconpath>c:\icon.ico</iconpath> -->
    </general>
    <files>
        <file>
            <source>your_rebol_script.r</source>
            <destination>your_rebol_script.r</destination>
        </file>
        <file>
            <source>C:\Program Files\rebol\view\Rebol.exe</source>
            <destination>rebol.exe</destination>
        </file>
        <!--put any other data files here -->
    </files>
    <!-- $FINDEXE, $TMPRUN, $WINDIR, $PROGRAMDIR, $WINSYSDIR -->
    <onrun>$TMPRUN\rebol.exe -si $TMPRUN\your_rebol_script.r</onrun>
</xpackerdefinition>

Just download the free XpackerX program and alter the above template so that it contains the filenames you've given to your script(s) and file(s), and the correct path to your Rebol interpreter. Run XpackerX, and it'll spit out a beautifully packaged .exe file that requires no installation. Your users do not need to have Rebol installed to run this type of executable. To them it appears and runs just like any other native compiled Windows program.

There are a variety of other options you can use to create distributable Rebol .exe programs. All such options involve creating self-extracting executable zip files ("SFX" files) that package the Rebol.exe interpreter together with your scripts. When run, the SFX files automatically open Rebol.exe, and execute your script on the command line. StubbieMan SFX is such a program, made specifically for creating packed executables, using a simple wizard interface. You can also use any other zip archiving application capable of creating SFX files. For example, PowerArchiver (version 6.11) is a popular free zip manager. To package Rebol executables with PowerArchiver, just follow the instructions to create a zip file that includes Rebol.exe and your script/data files, select "Actions->Make .EXE file" from the main menu, select "Create AutoRun SFX" and "Overwrite Files", then type "Rebol.exe| -s yourscript.r" into the field labeled "Command line after extracting" . It'll pop out a compact file executable with even less work than XpackerX or StubbieMan. Full instructions for creating self-extracting executables are included in the PowerArchiver help file. PowerArchiver and StubbieMan do not provide an option to change the resulting program icon. XpackerX is a bit tougher to use, but it does allow you to choose a specific icon for your program.

The most complex distribution option is to create a standard installation package. To do this, try NSIS, the NSIS SFX Tool (my favorite), Inno Setup or Pack-X2. These programs all create single file .exe install packages that provide users with a familiar installation routine, uninstall option, and a group icon in the "Start" menu, so that your Rebol program can be accessed and run like any other installed program. (Note that these programs are all for MS Windows. You'll need to find a different packaging system for other operating systems).

To create a self-extracting Rebol executable for Linux, first create a .tgz file containing all the files you want to distribute (the Rebol interpreter, your script(s), any external binary files, etc.). For the purposes of this example, name that bundle "rebol_files.tgz". Next, create a text file containing the following code. For the purpose of this example, save this script file as "sh_commands":

#!/bin/sh
echo ""
echo "Running... please wait"
echo ""
SKIP=`awk '/^__REBOL_ARCHIVE__/ { print NR + 1; exit 0; }' $0`
tail +$SKIP $0 | tar xz 
exit 0
__REBOL_ARCHIVE__

Finally, use the following command to combine the above script file with the bundled .tgz file:

cat sh_commands rebol_files.tgz > rebol_program.sh

The above line will create a single executable file named "rebol_program.sh" that can be distributed and run by end users. The user will have to set the file permissions for rebol_program.sh to executable before running it ("chmod +x rebol_program.sh"), or execute it using the syntax "sh rebol_program.sh". For more information about using this technique to create self-extracting Linux executables, see the article at http://linux.org.mt/article/selfextract.

18. Embedding Binary Data

You'll often need to use images and other binary data in your Rebol programs. For example, simple games often use graphic and sound files as part of their interface. As you've seen, there are many ways for Rebol to load in such binary data. You can read it from a hard disk, you can download it from the Internet, you can read it from just about any other local or networked storage medium, etc. When distributing your Rebol programs, however, those methods aren't always desirable. You don't want to require your user to download a number of images and sounds every time they play a simple game. They may not always have an Internet connection available. A possible alternative is to make a zip file or similar package that includes your program and all its supporting files. Creating and distributing such packages, however, can be overly complicated for simple scripts. Also, various operating systems use different compression types (zip, tar, etc.) and XpackerX/PowerArchiver/etc. only work in Windows. To eliminate those problems, Rebol provides a method to encode and include external files within the text of your programs. To see how it works, use the code below:

Rebol [Title: "Binary Embedder"]

system/options/binary-base: 64
file: to-file request-file/only
data: read/binary file
editor data

Type that program into your text editor, save it as a text file in "C:\embed.r", and then run it using any of the methods described in the previous section (try typing "do %\c\embed.r" into the Rebol interpreter). When run, the program will let you select a file, read it, and then display a binary representation of its data in the built-in editor. You can copy and paste the text of that printout directly into your program, assign it a variable name, and use it as if it had been read straight from a hard drive or another storage medium.

Here's an example. Download the picture below - you can use your web browser to go to the url, and then save the image to your hard drive. Or, you can download it using Rebol, as demonstrated earlier in the tutorial:

http://musiclessonz.com/test.png

Once you've downloaded the file, use the program above to select and convert it to binary data. You should get the following printout:

64#{
iVBORw0KGgoAAAANSUhEUgAAAFUAAABkCAIAAAB4sesFAAAAE3RFWHRTb2Z0d2Fy
ZQBSRUJPTC9WaWV3j9kWeAAAAU1JREFUeJztlzEOgzAQBHkaT7s2ryZUUZoYRz4t
e9xsSzTjEXIktqP3trsPcPPo7z36e4/+3qO/9y76t/qjn3766V/oj4jBb86nUyZP
lM7kidKZPFE6kydq/Pjxq/nSElGv3qv50vj/o59++hNQM6Z93+P3zqefAw12Fyqh
v/ToX+4Pt0ubiNKZPFE6Ux5q/O/436lkh6affvrpp38ZRT/99Ov6+f4tPPqX+8Ps
/meidCZPlM7kidKZPFE6kydKZ/JE6UyeKJ3JE6UzeaJ0Jk+UzuSJ0pk8UTMmvn8L
j/7l/nC7tIkonekLdXm9dafSmeinn376D/rpp5/+vv1GqBkT37+FR/9yf7hd2kSU
zuSJ0pk8UTqTJ0pn8kTpTJ4onckTpTN5onQmT5TO5InSmTxROpMnasbE92/h0b/Q
//jR33v09x79vUd/73XvfwNmVzlr+eOLmgAAAABJRU5ErkJggg==
}

Now copy and paste that data into the Rebol interpreter and assign it a variable label, like this:

picture: load 64#{
iVBORw0KGgoAAAANSUhEUgAAAFUAAABkCAIAAAB4sesFAAAAE3RFWHRTb2Z0d2Fy
ZQBSRUJPTC9WaWV3j9kWeAAAAU1JREFUeJztlzEOgzAQBHkaT7s2ryZUUZoYRz4t
e9xsSzTjEXIktqP3trsPcPPo7z36e4/+3qO/9y76t/qjn3766V/oj4jBb86nUyZP
lM7kidKZPFE6kydq/Pjxq/nSElGv3qv50vj/o59++hNQM6Z93+P3zqefAw12Fyqh
v/ToX+4Pt0ubiNKZPFE6Ux5q/O/436lkh6affvrpp38ZRT/99Ov6+f4tPPqX+8Ps
/meidCZPlM7kidKZPFE6kydKZ/JE6UyeKJ3JE6UzeaJ0Jk+UzuSJ0pk8UTMmvn8L
j/7l/nC7tIkonekLdXm9dafSmeinn376D/rpp5/+vv1GqBkT37+FR/9yf7hd2kSU
zuSJ0pk8UTqTJ0pn8kTpTJ4onckTpTN5onQmT5TO5InSmTxROpMnasbE92/h0b/Q
//jR33v09x79vUd/73XvfwNmVzlr+eOLmgAAAABJRU5ErkJggg==
}

You'll get the response below, indicating that the image has be defined and created:

make image! [85x100 #{
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF...}

Now you can use the variable "picture" as you would any other data. Display it, save it, transfer it between networked computers, etc. Here it is in a GUI:

view layout [image picture]

The example below displays a photo of my dog, and then saves it to the hard drive as a .png image:

dog: load 64#{
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
EQAAAABJRU5ErkJggg==
}

view layout [image dog]
save/png %dog.png dog

18.1 Compression

The code above can be shortened dramatically using the built in Rebol word "compress". Rebol's built in compression and decompression only work with text strings, so the binary embedder program provided earlier must be adjusted as follows to create compressed embedded data:

REBOL [Title: "Rebol Binary Embedder"]

system/options/binary-base: 64
file: to-file request-file/only
if not file [quit]
uncompressed: read/binary file

compressed: compress to-string uncompressed
; Note that the line above converts the binary data
; to a text string, and then compresses it.

editor compressed
alert rejoin ["Uncompressed size:  " length? uncompressed
    " bytes.  Compressed size: " length? compressed " bytes."]

IMPORTANT: To use the compressed version of the data above, you'll need to reverse the text-binary conversion after decompressing it. To do that, use the following code:

to-binary decompress {compressed data}

So, using the variables above, the following two lines of code display the same image:

view layout [image load uncompressed]
view layout [image load to-binary decompress compressed]

Here's a complete example demonstrating the size difference between raw and compressed embedded data:

; Here's an uncompressed embedded image:

image-uncompressed: load 64#{
iVBORw0KGgoAAAANSUhEUgAAAP8AAAEsCAIAAACDt/KoAAAAE3RFWHRTb2Z0d2Fy
ZQBSRUJPTC9WaWV3j9kWeAAAB9FJREFUeJzt3bGRHEkQBMETDaKd5v8UmlmzIaoz
MGtZ4QLUIBtBLXM//0lb/bz9D5BeY/3ay/q1l/VrL+vXXtavvaxfe1m/9rJ+7WX9
2sv6tZf1ay/r117Wr72sX3tZv/ayfu1l/drL+rWX9Wsv69de1q+9rF97Wb/2sn7t
Zf3ay/q1l/VrL+vXXmD9P1ICmCh4WkoAEwVPSwlgouBpKQFMFDwtJYCJgqelBDBR
8LSUACYKnpYSwETB01ICmCh4WkoAEwVPSwlgouBpKQFMFDwtJYCJgqelBDBR8LSU
ACYKnv7w+1f8W+fyP307B+a8MxA8Xf92Dsyx/jnjIPQPvD/xixn8G4wjqH/g/Qnr
r42jfuD9CeuvjaN+4P0J66+No37g/Qnrr42jfuD9CeuvjaN+4P0J66+No37g/Qnr
r42jfuD9CeuvjaN+4P0J66+No37g/Qnrr42jfuD9CeuvjaN+4P0J66+No37g/Qnr
r42jfuD9CeuvjaN+4P0J66+No37g/Qnrr42jfuD9CeuvjaN+4P0J66+No37g/Qnr
r42jfuD9CeuvjaN+4P0J66+No37g/Qnrr42jfuD9CeuvjaN+4P0J66+No37g/Qnr
r42jfuD9CeuvjaN+4P0J66+No37g/Qnrr42jfuD9CeuvjaN+IHi6/u0cmGP9c8ZB
6B8Inq5/Owfm9Nf/56/ftHP54T8szoFBDwPBRMHT3/F28W8dDgyyfuTt4t86HBjU
X780ACYKnpYSwETB01ICmCh4WkoAEwVPSwlgouBpKQFMFDz94fy8Ff/Ww4908W8d
Dgx6ZyB4uv7tHJhj/XPGQegfCJ6ufzsH5lj/nHEQ+geCp+vfzoE51j9nHIT+geDp
+rdzYI71zxkHoX8geLr+7RyYY/1zxkHoHwiern87B+ZY/5xxEPoHgqfr386BOdY/
ZxyE/oHg6fq3c2CO9c8ZB6F/IHi6/u0cmGP9c8ZB6B8Inq5/OwfmWP+ccRD6B4Kn
69/OgTnWP2cchP6B4On6t3NgjvXPGQehfyB4uv7tHJhj/XPGQegfCJ6ufzsH5lj/
nHEQ+geCp+vfzoE51j9nHIT+geDp+rdzYI71zxkHoX8geLr+7RyYY/1zxkHoHwie
rn87B+b01//K37mPf+twYNDDQDBR8PR3vF38W4cDg6wfebv4tw4HBvXXLw2AiYKn
pQQwUfC0lAAmCp6WEsBEwdNSApgoeFpKABMFT384P2/Fv/XwI138W4cDg94ZCJ6u
fzsH5lj/nHEQ+geCp+vfzoE51j9nHIT+geDp+rdzYI71zxkHoX8geLr+7RyYY/1z
xkHoHwiern87B+ZY/5xxEPoHgqfr386BOdY/ZxyE/oHg6fq3c2CO9c8ZB6F/IHi6
/u0cmGP9c8ZB6B8Inq5/OwfmWP+ccRD6B4Kn69/OgTnWP2cchP6B4On6t3NgjvXP
GQehfyB4uv7tHJhj/XPGQegfCJ6ufzsH5lj/nHEQ+geCp+vfzoE51j9nHIT+geDp
+rdzYI71zxkHoX8geLr+7RyYY/1zxkHoHwiern87B+ZY/5xxEPoHgqfr386BOf31
v/J37uPfOhwY9DAQTBQ8/R1vF//W4cAg60feLv6tw4FB/fVLA2Ci4GkpAUwUPC0l
gImCp6UEMFHwtJQAJgqelhLARMHTH87PW/FvPfxIF//W4cCgdwaCp+vfzoE51j9n
HIT+geDp+rdzYI71zxkHoX8geLr+7RyYY/1zxkHoHwiern87B+ZY/5xxEPoHgqfr
386BOdY/ZxyE/oHg6fq3c2CO9c8ZB6F/IHi6/u0cmGP9c8ZB6B8Inq5/OwfmWP+c
cRD6B4Kn69/OgTnWP2cchP6B4On6t3NgjvXPGQehfyB4uv7tHJhj/XPGQegfCJ6u
fzsH5lj/nHEQ+geCp+vfzoE51j9nHIT+geDp+rdzYI71zxkHoX8geLr+7RyYY/1z
xkHoHwiern87B+ZY/5xxEPoHgqfr386BOdY/ZxyE/oHg6fq3c2BOf/2v/J37+LcO
BwY9DAQTBU9/x9vFv3U4MMj6kbeLf+twYFB//dIAmCh4WkoAEwVPSwlgouBpKQFM
FDwtJYCJgqelBDBR8PSH8/NW/FsPP9LFv3U4MOidgeDp+rdzYI71zxkHoX8geLr+
7RyYY/1zxkHoHwiern87B+ZY/5xxEPoHgqfr386BOdY/ZxyE/oHg6fq3c2CO9c8Z
B6F/IHi6/u0cmGP9c8ZB6B8Inq5/OwfmWP+ccRD6B4Kn69/OgTnWP2cchP6B4On6
t3NgjvXPGQehfyB4uv7tHJhj/XPGQegfCJ6ufzsH5lj/nHEQ+geCp+vfzoE51j9n
HIT+geDp+rdzYI71zxkHoX8geLr+7RyYY/1zxkHoHwiern87B+ZY/5xxEPoHgqfr
386BOdY/ZxyE/oHg6fq3c2CO9c8ZB6F/IHi6/u0cmNNf/yt/5z7+rcOBQQ8DwUTB
09/xdvFvHQ4Msn7k7eLfOhwY1F+/NAAmCp6WEsBEwdNSApgoeFpKABMFT0sJYKLg
aSkBTJQ7LX0569de1q+9rF97Wb/2sn7tZf3ay/q1l/VrL+vXXtavvaxfe1m/9rJ+
7WX92sv6tZf1ay/r117Wr72sX3tZv/ayfu1l/drL+rWX9Wsv69de1q+9rF97Wb/2
sn7t9T/igalLLsvMjgAAAABJRU5ErkJggg==
}

; Here's a compressed version of the same data:

image-compressed: load to-binary decompress 64#{
eJzrDPBz5+WS4mJgYOD19HAJAtL/GRgYdTiYgKzm7Z9WACnhEteIkuD8tJLyxKJU
hiBXJ38f/bDM1PL+m2IVDAzsFz1dHEMq5ry9u3GijKcAy0Fh3kVzn/0XmRW5WXGV
sUF25EOmKwrSjrrF9v89o//u+cs/IS75763Tv7ZO/5qt//p63LX1e9fEV0fu/7ap
7m0qZRIJf+2DmGZoVER5MQiz+ntzJix6kKnJ6CNio6va0Nm0fCmLQeCHLVMY1Ljm
TRM64HLwMpGK/334Hf4n+vkn+1pr9md7jAVsYv+X8Z3Z+M/yscIX/j32H7sl/0j3
KK+of/CX8/X63sV1w51WqNj1763MjOS/xcccX8hzzFtXDwyXL9f/P19/f0vxz4f2
OucaHfmZDwID+P7Hso/5snw8m+qevH1030pG4kr8fhNC4f/34Z89ov+vHe4vAeut
SsdqX8T/OYUCv9iblr++f67R8pp9ukzLv8YHL39tL07o+3pekn1h/dDVBgzLU/d3
9te/Lki4cNgBmA6/lO+J/RPdzty8Rr5y94/tfOxsX6/r8xJK0/UW9vlH93/9oAzR
e09yKIUBVbT9/br/U/m7x6CU98VAAJS2ZPPF/197eEDhtfs9vX9rDzc6/v3qzUyo
nJA/dz76Y77tHw+w3gXlbEMpDKihza/+7/o/c3+DU54tDwsobR2/fXR/qYXBiV8T
t3eDEmpA/d9LDASK0y/tnz+H/Ynmt78E1vti7lAKA6pouxz/X7v+uR045ZFdRE6x
1q21pG7NiSzx1f5R40pvvdNn+oB1P4Onq5/LOqeEJgCemFy1KQgAAA==
}

view layout [image image-uncompressed]
view layout [image image-compressed]

The compressed version of the image data is exactly the same, but much smaller when included in your programs. When you use compression like that, just be sure to include the "to-binary decompress" words when loading the embedded data.

Using the short binary embedder program provided earlier, you can convert any type of file into embeddable text data. Images, sounds, videos, even entire executable programs can be included in your distributed code!

19. Modular Programming and Code Reuse

Rebol provides a fantastic array of easy to use programming tools built right into the language. As you've seen, Rebol's built-in words can accomplish useful "high-level" actions that can be the basis of simple programs. You can even use the interpreter as a powerful little swiss army knife utility that doesn't require any real programming (i.e., as a multiplatform text editor, calculator, email reader/sender, image viewer/editor, command interface for copying/pasting files, ftp uploader, etc.). For larger programs, however, the built in capabilities are merely simple building blocks. To build more complex applications, you need to _create_ new functionality by combining and using the native words, grammatical structures, and simple pieces of code. Language elements are just raw materials that can be put together to achieve more powerful and specific goals. Toward that end, a very important concept in programming is (drum roll...): the reuse of existing code.

Never re-invent the wheel. Reusing bits and pieces of existing code is essential if you want to become a productive programmer. The creation of functions is a basic way to implement code reuse - once you create a new function word to accomplish a given action, you can copy its definition and use it over and over again in your programs. That saves you the trouble of reinventing those actions every time they're needed in your programs. It also reduces the likelihood of introducing errors - old trusted code is less likely to contain bugs if it's already been tested and put to use in a variety of situations.

As demonstrated earlier, the built in word "do" opens and runs Rebol code that's been saved to a text file. You can use it to import existing modules of code, as if that code had been typed into your program. That existing code can contain function and variable definitions, new programmatic structures, and even complete programs of any length and level of complexity. Once those words and definitions have been imported into your program, you can use the included functions and variables as if they're native words in the language. You don't even necessarily need to know how they were created. Try typing in the following code example, and save it to "C:\play_sound.r".

Rebol [title: "play-sound"]

play-sound: func [sound-file] [
    wait 0
    ring: load sound-file
    sound-port: open sound://
    insert sound-port ring
    wait sound-port
    close sound-port
]

The code above creates a new function word "play-sound", which accepts a passed variable filename "sound-file" (that file must be a ".wav" file), and plays the sound through your computer speakers. You don't have to understand how the code works - just type it in and save it to C:\play_sound.r . Now, whenever you want to play a sound, you can include the code in your program:

do %/c/play_sound.r

And use the "play-sound" function just like any other built-in function word (the syntax is "play-sound {sound-file}"):

play-sound %/C/WINDOWS/Media/chimes.wav

Easy, right? You only have to type in the line "do %/c/play_sound.r" once in your program. After that, the word "play-sound" is defined, and you can use it wherever you need:

alert "Here's a sound:"
play-sound %/C/WINDOWS/Media/chimes.wav

alert "And here's another sound:"
play-sound %/C/WINDOWS/Media/chord.wav

alert "Now try choosing a .wav file from your hard drive:"
play-sound to-file request-file/file %/C/WINDOWS/Media/tada.wav

This whole concept becomes much more useful with the realization that (final drum roll...): You don't have to write everything yourself! There exists a community of developers around the world working to create useful pieces of code. Finding and learning to use modules of code, functions, and complete dialects created by other programmers will remain at the heart of your initial learning process, and will continue to play an important role in your efforts as a proficient developer.

Many self contained modules of Rebol code have been created to extend the built-in abilities of Rebol, and that list continues to grow as the language matures. Learning to use dialects and parts of programs created by others will make you a much more capable programmer. Existing modules of code can help you do high level, complex, and specific things with ease, so that you don't have to start from scratch in every programming effort.

In that way, learning to program is a lot like learning to use other types of technology that exist in our society. To call your friend on the phone, for example, you don't need to reinvent the telephone and all its electronic components. You don't need to manufacture any of those items, and you don't need to install miles of cable. You just need to know how to use the existing phone system. Furthermore, you can put that system to use in more complex operations that are functional to you at another level. Business owners rely on the phone to contact clients and employees, without necessarily caring how the system works. They just use it functionally as part of their higher level business goals. Existing code modules can work for programmers in a similar way. They make available high level functions that can be used to build even higher level, specific, and complex applications. You just need to know how to use them.

To reuse code modules, it's essential to first learn the language, so that you can understand code written by other developers. You may need to adjust and extend code written by others, so that it fits your needs more exactly. In most cases, however, you can just learn how to use the words in an imported module or dialect, execute a "do {filename}" command, and you're off and running with a whole new language extention. Here's an example:

The web site http://www.dobeash.com/it/ offers several free extension modules for the Rebol language. They provide a module called "RebGUI", for example, which extends the already powerful GUI syntax built into Rebol ("view layout..."). Using RebGUI, it's possible to easily display graphic widgets that aren't natively possible in Rebol. RebGUI constructs those components from the built in Rebol raw materials, and makes them reusable in your own programs. To use RebGUI, just download the files at the web site above, and unzip them to C:\ . Then type in the following code and save it as C:\rebgui_example.r. You can run it by any of the means described in the previous section ("do %/c/rebgui_example.r", etc.):

REBOL []

do %\c\rebgui.r

display "Grid" [
    table #WH options [
        "Day" left .5 "Time" left .3 "Name" left .3
    ] data [
        Monday 9:00 "John" Tuesday 9:30 "Jane" Wednesday 10:00 "Bob"
    ]
]

do-events

The code above makes use of some new commands that aren't part of the native Rebol language. Specifically, the functions and variables "display", "table", "#WH", "options", and "data" are defined in the rebgui.r file, and they add new functionality to the Rebol language. Using those words, as defined in rebgui.r, the above code displays the given data block [Monday 9:00 "John" Tuesday 9:30 "Jane" Wednesday 10:00 "Bob"] in a resizable GUI display that can be automatically sorted by clicking on column headers in the GUI. That type of display is a common requirement in modern programs that display lists of data ("database" applications), so the added commands are a welcome addition to the Rebol language. RebGUI contains a broad collection of additional functions that are useful in building intricate GUIs. To use them, you must first understand basic Rebol syntax, and then learn how to use the RebGUI language extensions within that syntax. Once you've done that, you can simply include the "rebgui.r" file in your programs, and use those language extensions as if they're part of the language. The key is to understand that RebGUI commands are built from native raw materials in the Rebol language, and to use them, all you need to do is import rebgui.r using the "do" command.

NOTE: rebgui.r is packaged with several additional files, which are in turn imported within the rebgui.r code. Those files contain "lower level" code that actually define the new words and grammar that make up RebGUI itself. They contain code that must all stay together with rebgui.r. Just as the above program is not complete without the included rebgui.r file, rebgui.r itself is not complete without its included files. As you begin to create longer and more complex programs, your source code will often consist of many separate source files tied together to make up a whole program. Managing and remembering which included files are required in your programs becomes more of an obligation as you build applications of greater complexity.

Here are some web links containing free modules that can help you accomplish useful programmatic tasks in Rebol:

http://www.hmkdesign.dk/rebol/list-view/list-view.r - a powerful listview widget to display and manipulate formatted data in GUI applications. Perhaps the single most useful additional to the Rebol GUI language.

http://www.dobeash.com/it/rebdb/ - a database module that lets you easily store and organize large amounts of data using the "SQL" database la