Home   Archive   Permalink

Sticky: Rebol 'Gotchas'

It's been noted that new Rebol users often run into some unexpected idiosyncrasies which cause frustration during even the most basic coding activities. This topic is meant to collect a list of troublesome quirks and peculiar 'gotchas' which you've run into, that don't (or didn't) make immediate sense to you, so that others can avoid any confusion you've worked through.

posted by:   Nick     29-Jan-2016/11:12:44-8:00

Missing closing bracket at end of script.
Since REBOL can't tell if you have closed all your blocks with the closing bracket until it has finished scanning the script and come up one bracket short, this is for me a common error. I have reduced that with the following procedure.
Use Carl's coding style of putting the opening bracket on the same line as the code that starts something requiring a bracket. Put the ending bracket on the same indentation level as the start of that line of code. BUT, the order of things is to type the first line with the opening bracket, THEN hit the "enter" key twice, THEN type the closing bracket, and AFTER that go back and type the code that belongs in the block. Like this:
if (condition) [ ;; opening bracket here
;; blank line here where you will go back and type code
] ;; ending bracket for the "if" function
This probably sounds stupidly simple to a non-beginner, but if you keep getting that error about the missing bracket, try this low-tech workaround.

posted by:   Steven White     31-Jan-2016/13:24:20-8:00

Example: In the US, at least, the standard shorthand for January 22, 2016 is 1/22/16. But here is what rebol thinks of that:
>> date? 1/22/16
** Syntax Error: Invalid date -- 1/22/16
** Near: (line 1) date? 1/22/16
The built in "help date" and "help date?" wasn't the least built helpful and it was time consuming to track down even this little bit of information:    
"3.2.2 Format
"The REBOL language is FLEXIBLE, allowing date! datatypes to be expressed in a VARIETY of formats. For example, the first day of March can be expressed in ANY of the following formats:
probe 1/3/1999
probe 1+++1999
probe 1999+++1 ;ISO format
I bolded the words FLEXIBLE, VARIETY, and ANY as either the documentation is a cruel joke or it needs to be re-written. Or, if the acceptable date formats can be set somewhere, it would be nice if this entry on date format would explain how.

posted by:   stever     31-Jan-2016/13:41:46-8:00

Steve White: I think most/all of the questions you have posted here through time are candidate "GOTCHAS". I think it is a big GOTCHA that single quotes can encompass a string but not produce a string. And the interpreter, again, isn't very helpful. Maybe you can link a number of your prior questions? I have found them nearly all to be things which also stung me.

posted by:   stever     31-Jan-2016/13:52:15-8:00

GOTCHA: Rebol's "helpful" implicit type conversion is often/usually the opposite of helpful.
A huge number of GOTCHAs stem, imo, from rebol doing all manner of internal type conversions to make something "fit" and, in that process, introducing bugs...which either blow up or not. "Not" being the worst of all, of course. I don't think rebol should secretly convert ANYTHING by default. Or, at least, it should make REAL plain what it is doing instead of just doing it and then vomiting further down the line.
It would be nice to give some examples here. I wish type conversion could be turned off and the intepreter would just blow as soon as it saw a mismatch. Maybe in Red or R4 we can get at least a little of haskell in that regard. I think this would eliminate 75% of newbie frustration, at least. ;-/

posted by:   stever     31-Jan-2016/14:02:17-8:00

Nick, On this thread I think you should occasionally edit anything for format, content, correctness, tone, etc. Ultimately I hope this thread will just get the point across and, ideally, a suggestion for the reader in a concise manner. On the other hand, when a candidate GOTCHA is being suggested I think the most important thing is to get the frustration across and worry about formalities and perfect delivery later. It is about user frustrations, after all.

posted by:   stever     1-Feb-2016/5:38:06-8:00

Punctuation: Feature or bug?
For those familiar with other languages, REBOL’s lack of punctuation can be a barrier to understanding. In other languages, punctuation provides clues to what is going on. If you see a line like
Function-name(argument-1, argument-2)
You know that a function is being called and is expecting two data elements. You can look for the function if you want to see what it does, or you can ignore it for the time being because you know it is a function that does something but you don’t really care what for now. In REBOL you see something like
Word-1 word-2 word-3
And if you are not familiar with all the REBOL functions you don’t know that word-1 is a function call and word-2 plus word-3 are two data elements expected by the function named word-1.    
Like many things, there are trade-offs. In a language with punctuation, a missing punctuation mark can give an error or it can let the program run but with unexpected results. A language with no punctuation can be harder to read.
To mitigate this reading difficulty, it helps to scan the REBOL function dictionary from time to time so that you recognize the function words when examining sample code. There also is a REBOL program on the internet that will color-code a REBOL scripts to highlight the REBOL function words:

posted by:   Steven White     1-Feb-2016/11:47:05-8:00

I agree. Associated with this, in the gitter red forum I suggested the IDE, at least, might incorporate a switch to show parentheses where the interpreter thinks they belong. I called referred to this as "training wheels" - though it was noted that even experienced rebol programmers can waste time trying to debug such a scope oversight. I doubt it will show up in 0.6 but I'm going to lobby hard as we get closer to 1.0. Although...parens are optional, right? So there might actually be possible even in Rebol to have the interpreter modify the code as part of a pretty print routine. Nick? Any thoughts on whether the interpreter could be easily bent to this task without having to hard code all the syntax logic in a parse?
This would save a LOT of time and a lot of frustrated would-be users. Later on, of course, the training wheels can be dropped.

posted by:   Steven W: re Punctuation     1-Feb-2016/14:13:26-8:00

Embracing the function paradigm
In the introduction to the first book about REBOL, Carl mentioned the idea that if you have prior programming experience it can help to forget what you know. But what does that mean, exactly? I think it means to forget the paradigm.    
In some languages you have syntax that defines sections of code. Maybe you have required punctuation. Words can be commands that make things happen. There are reserved words that can be used only in their intended way. REBOL is light on such requirements.
In REBOL the big thing is functions that act on data and return results. What does that mean? It means that if you call a function (which you do by just stating its name, not by any sort of “call xxx” syntax) and pass it some data (which you do by just stating after the function name the data needed by the function, and not by any notation involving parentheses), the function causes some data to be modified or to come into existence. Then what happens to it? Not necessarily anything, but you can pass that result to some other function, or you can set a word to refer to that result in case you have to “remember” it for later. Where is that result? Is it in some area of memory? I think the way to look at it is, it doesn’t matter. The result of a function can be a number, a string, a huge block of something; don’t worry about it. REBOL is providing a level of abstraction. Try to embrace that abstraction and not try to make it “like” something else in your mind. Analogies can help, but they can hinder also.
As an example, you can execute a function that obtains a file name:
That function returns a file name. What happens to it? It’s there, somewhere, but it is up to you to use it. Maybe you want to read that file into memory. You could say:
read request-file/only
The “request-file” function returned a file name to the “read” function which read the file. Where is the data? Somewhere in memory. If you want to refer to it, you have to assign a word to it:
FILE-DATA: read request-file/only
What if you want to “remember” the name of the file to report it along with the data? You could say:
FILE-DATA: read FILE-NAME: request-file/only
And so it goes, functions returning results which are used by other functions, and word being assigned to refer to those result. This is the REBOL paradigm. Embrace it.    
Views expressed here are those of the author only. He does not pretend to speak for Carl.

posted by:   Steven White     1-Feb-2016/16:06:48-8:00

A blizzard of words
If you are new to REBOL and looking at sample code, you see a blizzard of unpunctuated words. Where does one begin to make sense of it? I think that a beginner has two things working against him in this situation.    
The culture of REBOL recommends that “variable names” as it were should be short. So we see lots of words like “file” and “data.” In addition, a person coming from another background might be used to various headings or declarative in code, and sometimes those headings or declaratives are computer-ese words like “file” and “data,” like maybe for a file declaration, or a “data division.” So a first look at a REBOL sample can leave one wondering where to begin.    
Two things might be helpful. For reading code, one should become familiar with the REBOL functions, not necessarily to know in detail how they work, but to recognize them. That helps sort out functions from variables in sample code. For writing code, a nice little crutch is to put all your own variables in upper case, and reserve lower case for only the REBOL functions.    

posted by:   Steven White     1-Feb-2016/16:44:50-8:00

"Defining" "variables"
In some languages, especially compiled ones, one must declare variables, that is, indicate, near the beginning of the program, all the variable names that will be showing up later in the program. In REBOL there is not such requirement. One can code:
FILE-DATA: load %datafile.txt
and the "variable" FILE-DATA will come into being at that time, because it is not a variable so much as an indication that you want the word FILE-DATA to refer to the results of the "load" function.    
But, if you have roots in assembler language, you might like the look of all your variables lined up at the beginning of the program, maybe with a comment after each to indicate its use. You are free to do that:
FILE-DATA: none ;; Holds all data loaded from datafile.txt
... some intervening code
FILE-DATA: load %datafile.txt
But you don't have to do that, and the lack of that requirement is one thing that makes REBOL faster to code, the reduced amount of code. If you DO do that, it can come back to bite you, as in the following example:
COMPUTER-MODEL: "" ;; input value from some source
DISPLAY-MODEL: "" ;; value to be displayed somewhere else
... ;; enough code to make you forget how you spelled things
... ;; other code that changes the value of COMPUTER-MODEL
either equal? COMPUTER-MODEL "" [    
     DISPLAY-MODE: "unknown" ;; note the autopilot mis-spelling
] [
... ;; other code that eventually displays DISPLAY-MODEL
Note that you "declared" (unnecessarily) COMPUTER-MODEL and DISPLAY-MODEL. Later in the code, after you have forgotten what you did, you tried to set DISPLAY-MODEL to "unknown" but your fingers went on autopilot and typed the familiar computerese text DISPLAY-MODE. Then even later, you tried to display the value of DISPLAY-MODEL and found it did not have the expected value. This is because the word DISPLAY-MODE came into being when it was referred to, and this code ran just fine, although not with the expected result.    
At some time in the past Carl wrote a note on the internet about how people use REBOL like C or other languages, and should not. This might be one of those scenarios. If you are not required to say something, then save the effort and don't.

posted by:   Steven White     1-Feb-2016/17:25:16-8:00

Colon is not an assignment operator
That common REBOL notation of a word with a colon attached to it, followed by some value, looks a lot like a variable followed by an assignment operator (the equals sign in python, the colon-equals in some other languages), but it is not. In your beginning efforts with REBOL, you can think of it that way, but if you always think of it that way, then at some point it will not be that way, your thinking will not match reality, and you could get caught. Just be aware.
Look at the following example of a series and some operations on it.
>> array: [1 2 3 4 5 6 7 8 9]
== [1 2 3 4 5 6 7 8 9]
>> probe array
[1 2 3 4 5 6 7 8 9]
== [1 2 3 4 5 6 7 8 9]
>> length? array
== 9
>> subarray: skip array 4
== [5 6 7 8 9]
>> probe subarray
[5 6 7 8 9]
== [5 6 7 8 9]
>> length? subarray
== 5
>> poke subarray 3 11
== 11
>> probe subarray
[5 6 11 8 9]
== [5 6 11 8 9]
>> probe array
[1 2 3 4 5 6 11 8 9]
== [1 2 3 4 5 6 11 8 9]
The word "array" refers to the series of numbers one through nine. The word "subarray" refers to a point in that series starting at the fifth item. The syntax to define subarray does NOT mean to set up a variable called subarray and copy into it the series of numbers five through nine. It means that subarray refers to the array starting at the indicated spot. This can be seen when we poke a value into the third spot of subarray. The value of the word subarray changes, but so does the value of array, because they are not two separate "variables," but are words that refer to different spots in the same value.
Note that if you DO want to make a separate word that contains values copied from array, there is a way to do that, namely, the "copy" function. Just be aware that the notation shown in the example above does not copy anything.

posted by:   Steven White     1-Feb-2016/18:59:54-8:00

REBOL/VIEW Video Interface Dialect (VID) documentation
Probably because if that "paradigm problem" again, I always found the VID documentation hard to use. When I wanted to make a window and put stuff on it, I always seemed to be searching the existing documentation for examples, and then not understand exactly how to use them. So, to meet a need at work, I made my own VID manual. With the existing documentation and the list from Nick of all video styles, I tried to write an explanation of how each one works, with working examples. It isn't any new knowledge. It is a repackaging of what I could find elsewhere, in format that I personally find much easier to use. Now if I want to put something on a window, I pretend that my manual is complete documentation and just look up in it how to do something, and do it that way. I'm sure I am missing something, but I have enough that I can get acceptable results using it. I put it on the internet in case it is helpful to anyone else, at http://www.cobolrebol.com/pages/documentation/VIDforCOBOL.html.

posted by:   Steven White     1-Feb-2016/19:25:05-8:00

This is not really a "gotcha" so I am not offended if you delete it. It is more like a helpful tip for a beginner.
Here is a code sample harvested from rebol.org:
     "Return a substring from the start position to the end position"
     INPUT-STRING [series!] "Full input string"
     START-POS    [number!] "Starting position of substring"
     END-POS     [number!] "Ending position of substring"
] [
     if END-POS = -1 [END-POS: length? INPUT-STRING]
     return skip (copy/part INPUT-STRING END-POS) (START-POS - 1)
It is a function that takes a string of characters, plus a starting and ending position, and returns the substring indicated by those positions. The heart of it is the copy/part function on the last line of code. In fact, such a function probably isn't even necessary, because it can be replaced by just that last line. I don't know the story behind the creation of this function, but it wouldn't surprise me if the author kept forgetting how to use copy/part and wrote his own substring function in a style familiar to him.
So the point is, when you write something that you suspect could have some generality, try to encapsulate it in a general-purpose function and put it in a REBOL script (like myfunctions.r) along with all such functions you accumulate. Then, when you write a new program, at the front, put the line "do %myscripts.r" and all those functions that you have created over time will be available.    
If you go to the REBOL command prompt and type "source (function-name)" you will get the source code for the indicated function. For those functions that are not "native" (written in C for a specific line of computers), you will see that parts of REBOL are written in...REBOL. These functions written in REBOL are, I believe, referred to in the lingo as "the mezzanine." If you start building your own mini-mezzanine, you will, over time, develop a library of functions tailored to your own specific uses. This library of functions tailored to your specific uses will be a lot easier for you to use than some other library you had to search for on google and then study for its useful parts. It could speed up your own programming significantly.

posted by:   Steven White     1-Feb-2016/20:07:54-8:00

Steven White your examples were helpful to me. Thanks.
The array example...tricky. Interesting how it's not a new variable.
Your VID reference chart is gone/bad link.

posted by:   Sam     12-Feb-2016/21:03:24-8:00

Sorry about that link. The dot at the end of the sentence got into the link, making it end in "html" Here it is, dotless:

posted by:   Steven White     13-Feb-2016/11:50:13-8:00

"The array example...tricky. Interesting how it's not a new variable."
You can regard it as REBOL tries hard not to copy data, when it can avoid it, and many bugs can arise from unintentionally modifying a series that should have been copied. On the other hand, it can be used to make programs fast and small.
For all series!, you need to distinguish between functions that copy or modify a series that is input to the function. In REBOL 3, the functions that have "modifies" in their help header, will modify the input value. Others will copy it. This help is not consistently available in REBOL 2.
Copying has multiple depths. Blocks of strings can be individually copied or not.
The COPY function does for example only copy the block that is passed to it, not any blocks or strings that are inside it. For that, you need to use COPY/DEEP, to also copy all series inside it.
Objects are partially copiable, though you can't use the COPY function for this. There are third party mezzanines that do this, like a DEEP-COPY which I use a lot.
You can also brute-force copy an object of any complexity using LOAD MOLD/ALL, which has better speed and memory performance than DEEP-COPY, but it is not safe to use on all datatypes, and won't work with precision numbers, due to limitations in the implementation of MOLD and LOAD. At least not on REBOL 2.
The SAME? function will help to find out whether two series are actually the same one.

posted by:   Henrik     16-Feb-2016/7:47:08-8:00

Here is another one that gets me now and then, though less often now.
In languages where there are "statements" or "commands," the word "if" often is available as a command and is followed by some recognizable conditional statement, like (X > 1).
In REBOL, it seems that everything is a function, and "if" (and its cousin "either") are followed by something that evaluates to true or false. That could be a condition, but it also could be a word or another function that returns something that evaluates to true or false, AND, anything that is not "none" evaluates as true, and "none" evaluates as false. And "none" is the result of many functions that don't return anything, like a "find" that finds nothing, or a "request-file" that is canceled. So you can have code like this:
>> x: 21.3
== 21.3
>> Y: "This is a test"
== "This is a test"
>> Z: none
== none
>> either x [print "true"] [print "false"]
>> either y [print "true"] [print "false"]
>> either z [print "true"] [print "false"]
Now, the relevant point for a beginner is that for some people, depending on background, they look at that and say, "Well, yeah, duh, of course values that are not (none/null/unedfined) are false and anything else is true, everyone knows that," but other people, depending on background, look at that and say, "What's going on there, you can't have something after an 'if' statement that is not a condition, that makes no sense." And then, depending on background, each person thinks that what he knows is the only way, and by not being aware of another way, is unable to understand why the other person, or he himself, could be having a problem.    
When I encountered REBOL, my main background was COBOL, some exposure to block-structured languages like ALGOL, and a couple assembler languages. When I first saw REBOL, my reaction was along the lines of, "But this makes no SENSE!" Now that I realize I am just embracing a different paradigm, things are easier.

posted by:   Steven White     22-Feb-2016/10:22:52-8:00

@Steven White-Thanks for all the VID work. Much appreciated. This is a really good thread.

posted by:   Sam     2-Mar-2016/14:03:59-8:00

Here is item that "got" me for a while, and is interesting not necessarily in itself, but for the process by which I found a solution. When you fill up a large text area on a VID window, you can't just set the text value and show the area. There is another attribute, called "line-list," that must be set to none. It is explained here:
This probably is based on my own reality of the "good old days" when computers were accompanied by many pounds of paper manuals, but I sort of expected to find, somewhere, a manual of all the VID styles with detailed explanations of how to use them. The information I wanted did exist, and I did find the above detailed explanation, but it felt like a more "by the way" process, as in "and by the way, here are some extra documents that show how to use text styles," and, "and by the way, if you fill a big text area you have to be sure to set the line-list to none."    
So the information did exist, and I did find it, but the process felt a bit uncomfortably chaotic. Maybe I'm just whining. Maybe the concept of community effort is outside my personal reality. I do have a couple of my own "by the way" documents in the works, so maybe at some point in the future all this will seem normal to me and I will wonder what all the fuss was about.    

posted by:   Steven White     8-Mar-2016/11:10:33-8:00

I was "gotten" again just today by not remembering that a single blank character is not the same thing as a one-byte blank string, as shown in the following example:
R E B O L [ ]
     if equal? CHARACTER " " [
         print "Equal to one-byte blank string"
     if equal? CHARACTER #" " [
         print "Equal to a blank character"

posted by:   Steven White     29-Aug-2016/17:18:57-7:00

The documentation for Encryption is incorrect in some places.
Under "RSA Public Key Encryption" it says this ...
p, q, dmp1, dmq1, iqmp
Parts of the secret key, used to improve the performance of private key operations. If only n, d and e are saved for a private key then the key can still be used for private key operations, but those operations will be slower than for a key that contains p, q, dmp1, dmq1 and iqmp.
This is incorrect, if you use the /private refinement then the p, q, dmp1, dmq1 and iqmp MUST exist (or you will get a "Invalid argument: none" error) and they must match the original data that was generated when the key was created (or you will get a "Block did not return a value") error.
Also, the documentation makes it look like you can specify the refinements at the end, like this:
rsa-encrypt rsa-key data /decrypt /private /padding padding-type
This is incorrect too, you must specify the refinements like this:
rsa-encrypt/private rsa-key data
rsa-encrypt/private/decrypt rsa-key data
Finally, if you are trying to decrypt some binary data and the key is incorrect (like you used the public key when it should have been the private key or vice versa, or if you used the wrong key all together) then you will get a "Block did not return a value" error. It obvious that you would get an error, but I only mention it because the error message doesn't give you any type of clue of what went wrong.

posted by:   Brian     29-Sep-2016/2:05:06-7:00

Watch your typing autopilot.
I get so used to typing a word followed by a colon that sometimes I get on autopilot and will type something like:
append data-name-1: rejoin [
Note the colon after data-name-1. And then, after I have typed it unconsciously, I go back and read that code looking for the bug I created, and I don't even SEE the colon.    

posted by:   Steven White     5-Jul-2017/17:25:50-7:00

Watch your typing autopilot -- autopilot colons, part II
I once wrote:
     return: false
rather than:
     return false
The ensuing debugging session was rather interesting, as basically nothing would work, not even my usual tracing/logging functions.
That's the day I really learned the value of:

posted by:   Sunanda     27-Aug-2017/12:07:09-7:00



Type the reverse of this captcha text: "k c e h c - e l c i t r a"