REBOL Beginners

REBOL Video Tutorials

I can't believe I missed these tutorials! But between the frantic 12-14 hour a day coding sessions I have these days to meet strict deadlines, I miss a lot of things, including the piece and quiet to think properly about some code to do it correctly.

I haven't run through them yet, but if you are a beginner and want to hear and see your tutorials about REBOL rather than reading about them, well, here's a good start. Many thanks to Nick Antonaccio for creating them. Enjoy!
|

Steven's Place

I'd like to point out Steven's space. He's a beginner in REBOL and has only been working with it for a week, but he's doing tremendous progress, already building a To-do application with VID.

And oh, hey, he's using my LIST-VIEW as well. He says it's faster and easier to use than the list views that can be found in Java Swing and what's possible with Visual Basic. It's a nice think to know that VID isn't all bad. Happy
|

AltME? AltWHAT?

It's always a joy to see newcomers to the REBOL language. You may be one of them and if so, welcome! We don't serve any beverages or ask you to sit in a comfy chair, but we hope you'll come to enjoy the language as much as we do. Unfortunately there are separated pockets of users in different places, mainly shaped by the communication form and ease of access. There isn't really one universally accepted place to hang out. But these places are where there is some action. Read More...
|

MacOSX Terminal Trouble

MacOSX Tiger doesn't have the best terminal implementation: It consumes a lot of CPU just by outputting text on screen on slower Macs. While it has since been upgraded significantly for Leopard (still CPU intensive, but not nearly as much), you may still be using Tiger on a slower, older Mac.

My MacMini PPC G4 1.25 Ghz is therefore eating a considerable amount of CPU, about 10-20%, when REBOL is doing nothing but displaying the network wait indicator in the terminal window! This is for example the case, when you are using Rugby as a server, or when REBOL/Services is running.

Fortunately this can be turned off with:
system/options/quiet: true

And then REBOL goes really quiet and less CPU hungry. Happy

This also eliminates network access output to the console, if you want to control better what is displayed when a network resource is accessed from REBOL.

Enjoy!
|

System/Words

Ever needed to create a function that has a refinement with the same name as an existing word or function in REBOL?

All words are stored in SYSTEM/WORDS, so if you need to, you can access every function or data using that path:

>> system/words/now
== 2-Dec-2007/8:12:36+1:00


So if you have a function with a refinement called FALSE, the normal FALSE word inside the function will be overridden with the state of the refinement. To access it again, use SYSTEM/WORDS/FALSE:

test: func [a b /false] [
a + b ; exciting, but irrelevant stuff happens here.

; this function should return false when /false is used
either false [system/words/false][true]
]


Outside the function, FALSE behaves like normal. Enjoy!
|

Natives vs. Actions vs. Mezzanines

If you're a bit curious to learn some deeper aspects to how REBOL is built, it's practical to know the difference between native functions and mezzanine functions.

When you use the SOURCE function on another function, sometimes, you'll get the source code for that function and other times, you won't. Natives don't output source code:

>> source insert
insert: native [
{Inserts a value into a series and returns the series after the insert.}
series [series! port! bitset!] "Series at point to insert"
value [any-type!] "The value to insert"
/part "Limits to a given length or position."
range [number! series! port! pair!]
/only "Inserts a series as a series."
/dup "Duplicates the insert a specified number of times."
count [number! pair!]
]


Well, what is a native? Natives are the basic method for doing something. They are written in C, and therefore you can't see its source code in the console, because the function is part of the very core of REBOL and can't be altered directly.

Mezzanine functions are built of natives or a combination of natives and other mezzanine functions.

In the case of the native function INSERT, it's used to build other functions, like APPEND.

If you look at the output (too long to paste here) of:
>> source append

...you'll find the INSERT function inside it.

This is one of the reasons that REBOL has so many functions despite having such a small executable!

You can see the complete list of native functions, by calling up:
>> help native!

You can do that, because native functions have their own datatype, native!, while mezzanine functions are of type function!.

A third type called action! also exists, which is similar to natives, except that they are internally implemented differently as methods, where natives are more like normal C functions. For you, the REBOL programmer, there's no real need to know the difference between actions and natives.

Thanks to John Niclasen and Gabriele Santilli with helping with this blog post via AltME!
|

Loading Configuration Data

I’m always pleased at how REBOL allows you to skip work that you’d normally have to do in other languages, such as loading configuration data and making use of this data in your programs.

Normally, you might have to:

- Invent a configuration file format.
- Decide on a method to store configuration data in a file.
- Decide on a method to load and parse configuration data and use it in the program.

or if you are a former XML fan, you’d find a bigarse library to parse XML files, written out with an XML generator. Bloated. Slow.

If you like a challenge, you can do all that in REBOL. REBOL has a fine parser, that will easily parse strings of text read from disk.

But REBOL can do all of this without you writing a lot of boring code.

The magic trick to use here is LOAD. LOAD is pretty good at loading data and you can use LOAD on files, internal data and network resources.

If you create a file, say, %config.r, which contains:

name: "My Name"
address: "My Address"
registration-number: 123456789

and nothing else, you can LOAD this file into a block in one go:

>> load %config.r
== [name: "My Name" address: "My Address"...

Now what REBOL does here is more than just reading the data off disk; It creates a block of valid REBOL elements of the correct datatypes. You now actually have a valid piece of data that is ready to be further processed or run. Yes, run!

Because when you DO the loaded data, the data is suddenly code that is executed. The items "name:" "address:" and "registration-number:" become variables in the system, with their respective values assigned to them.

The full piece of code would be:

do load %config.r

This is actually all you need to do! Ridiculously simple!

You can do this, because data and code are the same thing in REBOL. Imagine the possibilities... Happy
|

Checking block structures

Do you have a large block of data that you want to check the structure of?

PARSE is a good way to do that, since it returns TRUE if it can parse the entire block properly. PARSE happens also to be very fast.

Our data should be a block of blocks:
data-block: [
[1 2 3]
[4 5 6]
[7 8 9]
]


So you can simply check that each entry is a block:
>> parse data-block [any block!]
== true


Let's sabotage our data block:
data-block: [
[1 2 3]
none ; oops!
[4 5 6]
[7 8 9]
]

>> parse data-block [any block!]
== false


Simple!
|

Using or not using ATTEMPT

ATTEMPT is a really nice function. It makes it simple for you to skip errors in code if a part of your code fails. Such as:
>> a: 2
>> b: 0
>> attempt [a / b]
>> none ; We're fine. Keep moving.

This is good if you don't really care about a math error, it's pretty obvious what goes wrong and just want to keep going.

I use this combination often:
any [attempt [a / b] "Math Error"]

As it's simple enough to debug by PROBE'ing a or b.

Therefore if you are building a larger script for a customer, and don't want the console output pop up suddenly in his/her face with strange error outputs, it can be quite tempting to just say:
attempt [
huge amount of code, perhaps an entire application
]

ATTEMPT will not only keep your code running now, it will also completely hide otherwise obvious errors. If you use it like this, you lose of control over your code. Your application will not only not crash, by not responding to a user action, but you won't know at all what goes wrong.

Never use two nested ATTEMPTS to print the number of candybars per child:

unit: " candybars per child"
print any [
attempt [
join any [
attempt [candybars / children] default-value
]
unit
]
"Uhmm.. error!"
]

Any number of things could be wrong in even this small bit of code:

  • default-value might not be set or is the wrong type

  • candybars and/or children might not be set or are the wrong type

  • children might be 0.

  • Heck JOIN may even have been redefined by accident in a different section of your program! You won't notice...


It really is much better to do proper handling of errors than just to ignore them in the long run, It leads to unpredictable behavior and frustrating all-night debugging sessions.
|