REBOL/Core Changes

Document Version 1.1
Updated 6-May-2002
REBOL Technologies
HTTP://www.rebol.com

Table of Contents

1. Version 2.5.2
      1.1. CONSTRUCT Object Creator
      1.2. LOAD No Longer Evaluates Script Header (Important)
      1.3. HELP Expanded
      1.4. SUFFIX? Function Added
      1.5. SIGN? Function Added
      1.6. COMPONENT? Function Added
      1.7. SEND Function Updated
      1.8. Miscellaneous Fixes
            1.8.1. TYPE? (As used in PARSE)
            1.8.2. MOLD/ALL
            1.8.3. FTP on IIS and FTP Links
2. Version 2.5.1
      2.1. Source Code Form for Values of NONE, TRUE, etc.
      2.2. Less Aggressive Evaluation (Important!)
      2.3. COMPOSE/ONLY Inserts Blocks
      2.4. REMOVE-EACH - Easy Series Element Removal
      2.5. ATTEMPT for Error Handling
      2.6. EXTRACT Function Updated
      2.7. SAVE to Memory
      2.8. SEND Refinements /Subject /Attach
      2.9. Difference for Date/time
      2.10. System Port Added
      2.11. Interpreter Fixes
      2.12. Networking Fixes
      2.13. Other Function Fixes



1. Version 2.5.2


1.1. CONSTRUCT Object Creator

We've added a "light-evaluation" object creator to provide a higher level of security for imported data objects. The function is called CONSTRUCT and it makes new objects, but without a normal evaluation of the object's specification (as is done in the MAKE and CONTEXT functions).

When you CONSTRUCT an object, only literal types are accepted. Functional evaluation is not performed. This allows your code to directly import objects (such as those sent from unsafe external sources such as email, cgi, etc.) without concern that they may include "hidden" side effects using executable code.

CONSTRUCT is used in the same way as the CONTEXT function:

obj: construct [
    name: "Fred"
    age: 27
    city: "Ukiah"
]
but, no evaluation takes place. That means object specifications like:

obj: construct [
    name: uppercase "Fred"
    age: 20 + 7
    time: now
]
do not produce their evaluated results.

The CONSTRUCT function is useful for importing external objects. For example, loading preference settings from a file can done with:

prefs: construct load %prefs.r
Similarly, you can use CONSTRUCT to load a CGI or email response.

To provide a template object that contains default variable values (similar to MAKE), use the /WITH refinement. The example below would use an existing object called standard-prefs as the template.

prefs: construct/with load %prefs.r standard-prefs
The CONSTRUCT function will perform evaluation on the words TRUE, FALSE, NONE, ON, and OFF to produce their expected values. Literal words and paths will also be evaluated to produce their respective words and paths. For example:

obj: construct [
    a: true
    b: none
    c: 'word
]
The obj/a value would be logical TRUE, obj/b would be NONE, and obj/c would be WORD.


1.2. LOAD No Longer Evaluates Script Header (Important)

Script header objects are now created by the CONSTRUCT function and are no longer evaluated. The LOAD function can be used safely without the need to use LOAD/ALL to inspect a script header prior to evaluation.

This change provides a greater level of default security when the LOAD function is used to load REBOL data (in CGI, VID fields, data files, libraries, etc). The change should affect few scripts (only those that depend on evaluated header variables, which is rare).


1.3. HELP Expanded

Help can now be used to explore the fields of an object in a user-friendly format. For example, typing this line at the prompt:

help system
will produce this result:

SYSTEM is an object of value:
   version         tuple!    1.0.4.3.1
   build           date!     1-May-2002/13:31:11-7:00
   product         word!     Link
   components      block!    length: 45
   words           object!   [unset! error! datatype! context! native! action! ...
   license         string!   {REBOL End User License Agreement IMPORTANT. READ ...
   options         object!   [home script path boot args do-arg link-url server...
   user            object!   [name email home words]
   script          object!   [title header parent path args words]
   console         object!   [history keys prompt result escape busy tab-size b...
   ports           object!   [input output echo system serial wait-list]
   network         object!   [host host-address]
   schemes         object!   [default Finger Whois Daytime SMTP POP IMAP HTTP F...
   error           object!   [throw note syntax script math access command resv...
   standard        object!   [script port port-flags email face sound]
   view            object!   [screen-face focal-face caret highlight-start high...
   stats           native!   System statistics. Default is to return total memo...
   locale          object!   [months days]
   user-license    object!   [name email id message]
This works for other types of objects as well as user-created objects. The code below would display the contents of the text-face object created by a View layout:

out: layout [text-face: text "test"]

help text-face
Sub-objects can also be viewed. They are specified as paths. For example, to see the options object of the system object:

help system/options
The result would look something like this:

SYSTEM/OPTIONS is an object of value:
   home            file!     %/d/rebol/link/
   script          file!     %/d/rebol/link/ranch/utilities/console.r
   path            file!     %/d/rebol/link/ranch/
   boot            file!     %/d/rebol/link/rebol-link.exe
   args            none!     none
   do-arg          none!     none
   link-url        string!   "tcp://localhost:4028"
   server          none!     none
   quiet           logic!    true
   trace           logic!    false
   help            logic!    false
   install         logic!    false
   boot-flags      integer!  2064
   binary-base     integer!  16
   cgi             object!   [server-software server-name gateway-interface ser...
In addition, the search feature in help now provides more information about matches that were made. If you type:

help "to-"
You will now see:

Found these words:
   caret-to-offset native!   Returns the offset position relative to the face o...
   offset-to-caret native!   Returns the offset in the face's text correspondin...
   to-binary       function! Converts to binary value.
   to-bitset       function! Converts to bitset value.
   to-block        function! Converts to block value.
   to-char         function! Converts to char value.
   to-date         function! Converts to date value.
   to-decimal      function! Converts to decimal value.
   to-email        function! Converts to email value.
   to-event        function! Converts to event value.
   to-file         function! Converts to file value.
   to-get-word     function! Converts to get-word value.
   to-hash         function! Converts to hash value.
   to-hex          native!   Converts an integer to a hex issue!.
   to-idate        function! Returns a standard Internet date string.
   to-image        function! Converts to image value.
   to-integer      function! Converts to integer value.
   to-issue        function! Converts to issue value.
   to-list         function! Converts to list value.
   to-lit-path     function! Converts to lit-path value.
   to-lit-word     function! Converts to lit-word value.
   to-local-file   native!   Converts a REBOL file path to the local system fil...
   to-logic        function! Converts to logic value.
   to-money        function! Converts to money value.
   to-none         function! Converts to none value.
   to-pair         function! Converts to pair value.
   to-paren        function! Converts to paren value.
   to-path         function! Converts to path value.
   to-rebol-file   native!   Converts a local system file path to a REBOL file ...
   to-refinement   function! Converts to refinement value.
   to-set-path     function! Converts to set-path value.
   to-set-word     function! Converts to set-word value.
   to-string       function! Converts to string value.
   to-tag          function! Converts to tag value.
   to-time         function! Converts to time value.
   to-tuple        function! Converts to tuple value.
   to-url          function! Converts to url value.
   to-word         function! Converts to word value.


1.4. SUFFIX? Function Added

The SUFFIX? function is a helper function that returns the file "extension" portion of a filename or URL. For example:

>> suffix? %into.txt
== %.txt

>> suffix? http://www.rebol.com/docs.html
== %.html

>> suffix? %test
== none

>> suffix? %test.it/file
== none
SUFFIX? can be useful when selecting files from a directory. The example below will only select html and htm files:

foreach file load %. [
    if find [%.html %.htm] suffix? file [
        browse file
    ]
]


1.5. SIGN? Function Added

The SIGN? function returns a positive, zero, or negative integer based on the sign of its argument.

print sign? 1000
print sign? 0
print sign? -1000
The sign is returned as an integer to allow it to be used as a multiplication term within an expression:

new: 2000 * sign val

if size > 10 [xy: 10x20 * sign num]


1.6. COMPONENT? Function Added

COMPONENT? is a helper function that checks for the existence of a named REBOL component.

if component? 'crypt [print "Encryption available."]

if not component? 'sound [print "No sound."]


1.7. SEND Function Updated

The SEND function now includes a /SHOW refinement that will show all TO recipients in the header. By default, recipients are not normally shown.

send/show [bob@example.com fred@example.com] message
In addition the FROM field will include the sender's name as well as an email address. The string in system/user/name is used as the from address. For example, if:

system/user/name: "Fred Reboller"
Then when the email is sent, the from field will now appear as:

From: Fred Reboller <fred@example.com>
If system/user/name is NONE or empty, it will not be used.

Finally, some problems in the /ATTACH refinement have been fixed. Attachments of the form:

send/attach user content [[%file.txt "text message"]]
should work properly now. See 2.5.1 notes on SEND for more information about /ATTACH.


1.8. Miscellaneous Fixes


1.8.1. TYPE? (As used in PARSE)

Fixed the problem reported in the TYPE? function that caused the datatype error in PARSE. Code of the form below will work properly now:

parse [34] reduce [type? 34]
parse [34.5] reduce [type? 34.5]


1.8.2. MOLD/ALL

Fixed the problem with function molding when /ALL refinement is provided.

load mold/all context [test: func [arg] [print arg]]


1.8.3. FTP on IIS and FTP Links

Two fixes:

  1. When connecting to a Microsoft IIS based FTP server Rebol did not recognize folders correctly. They were marked as type 'directory but no slash was appended to the file name as done with other types of FTP servers.
  2. In FTP soft-links can now be identified. They can now return an file type of 'LINK.
Thanks: Cal and Reichart at Prolific.com for submitting the above FTP fixes.



2. Version 2.5.1


2.1. Source Code Form for Values of NONE, TRUE, etc.

To better support persistent values between SAVE, MOLD, and LOAD, a new syntactic element has been added to REBOL.

In the past, the source code representation of values like NONE and TRUE required evaluation in order to convert those words into their actual values. For example:

load "NONE"
would return the word NONE, not the value none. This required that your code either evaluate the result (with DO, REDUCE, or TRY) or manually convert the NONE word with code such as:

if value = 'none [value: none]
Thus, if you were storing REBOL data using MOLD or SAVE functions, when you read the data back in, you would need to either evaluate it (e.g. with REDUCE) or add checks for a few specific types of words (as shown above).

To better handle this situation with the literal expression of NONE, TRUE, FALSE, and other values that require evaluation, a new syntactic form has been added to the language:

#[datatype value]
Where datatype indicates the datatype and value provides its value. For simple datatypes such as NONE, TRUE, and FALSE the shorthand form:

#[word]
is also allowed. For example:

#[none]
expresses the value NONE, not the word NONE, even with unevaluated code or data. Similarly,

#[true]
#[false]
express the values of TRUE and FALSE within non-evaluated code.

The LOAD, DO, and other source translating functions have been expanded to accept this new syntax. The example below helps show the change:

block: load " none #[none] true #[true] "

foreach value block [print type? value]

word
none
word
logic
The literal expression of REBOL objects is also allowed by this new format. For example the non-evaluated expression:

#[object! [name: "Fred" skill: #[true]]]
is equivalent evaluating:

make object! [
    name: "Fred"
    skill: true
]
Thus, a persistent (mold/load symmetric) form of objects now becomes available to programmers.

To create or save source code or data using these new datatype expressions, the MOLD and SAVE functions have been given a new refinement called /ALL. This refinement will output the new #[] format for necessary values. For example:

mold/all reduce ["Example" true none time]
word return the string:

["Example" #[true] #[none] 5-May-2002/9:08:04-7:00]
Similarly, using SAVE/ALL would store the above expression to a file.


2.2. Less Aggressive Evaluation (Important!)

Variables are no longer aggressively evaluated.

In previous versions of REBOL, variables that held set-words, parens, paths, and other evaluative datatypes would be evaluated on reference. That is no longer the case.

For example, in earlier versions, if you wrote:

a: first [b/c/d]
print a
the result would be an evaluation of b/c/d. This evaluation caused problems because it is more common to reference such data, not evaluate it. For instance, you want to be able to write:

data: ["test" A: mold/only (10 + 2.5)]

foreach value data [print value]
and smoothly traverse the elements of the data block as simple values. You would not want those values to self evaluate.

This change to evaluation has some deeper implications. For example, it affects any function that specifies literal values within arguments. For example, code such as:

f: func ['word] [print word]
The REBOL design definition of a literal function argument is to accept the argument always as a literal value and NOT evaluate it. However, in the actual implementation it turned out that an evaluation would normally occur when the variable was referenced. (As part of the PRINT in this case.)

For instance, if you passed:

f a/b/c
within the function, the reference to the word would cause the path to be evaluated at that point. Hence, if you referred to the word argument three times, each time it would be evaluated.

This implicit and "aggressive" evaluation, while interesting, was not intuitive, created hard to find errors, and generated error messages that were difficult to understand.

Consider the case where the set-word datatype might be passed as the argument:

f test:
The set word (test:) would be evaluated where WORD appears (in the PRINT line), and that operation would require an argument. The code would produce an error message that would tell you that set requires an argument. Yet, you would see no set within your code. It would look like an interpreter flaw, when in fact it was doing precisely what you asked.

Since the vast majority of REBOL programs do not rely on this type of evaluation, we've taken it out. This cleans up the semantics of literal arguments, but it also means that where programs depend on passing non-literals and assume that evaluation occurs, they do not. That will break some code, but it is rare. (For example, in the entire source code base of REBOL Technologies, there was only one such case.)


2.3. COMPOSE/ONLY Inserts Blocks

The COMPOSE function now has an /ONLY refinement similar to the INSERT/ONLY refinement. When /ONLY is specified, blocks that are inserted are inserted only as blocks, not as the elements of the block (the default). A REDUCE on the block is not required.

For example:

>> block: [1 2 3]

>> compose [example (block)]
== [example 1 2 3]

>> compose [example (reduce [block])]
== [example [1 2 3]]

>> compose/only [example (block)]
== [example [1 2 3]]


2.4. REMOVE-EACH - Easy Series Element Removal

The new function REMOVE-EACH works in a similar fashion to FOREACH and makes removing values from strings, blocks, and other series much easier.

Also, in most cases REMOVE-EACH is many times faster than using a WHILE loop and the REMOVE function.

The format of REMOVE-EACH is identical to FOREACH except that it uses the result of the block expression to determine removal. REMOVE-EACH iterates over one or more elements of a series and evaluates a block for each. If the block returns FALSE or NONE, nothing is removed, but if the block returns any other value, the item (or items) are removed.

remove-each value series [expression]
Similar to FOREACH, REMOVE-EACH can operate on multiple elements from the series (and uses the appropriate skip to get to the next set of elements):

remove-each [val1 val2 val3] series [expression]
Note that in addition to modifying the series, REMOVE-EACH also returns the series as its result.

Here are a number of examples.

To remove the odd numbers from block:

>> blk: [1 22 333 43 58]
>> remove-each item blk [odd? item]
== [22 58]
>> probe blk
== [22 58]
To remove all numbers greater than 10 from block:

>> blk: [3 4.5 20 34.5 6 50]
>> remove-each item blk [item > 10]
== [3 4.5 6]
>> probe blk
== [3 4.5 6]
To remove all directories from a directory listing:

>> dir: load %.
>> remove-each file dir [#"/" = last file]
== [%calculator.r %clock.r %console.r %find-file.r...]
To keep only the directories in the listing:

remove-each file load %. [#"/" <> last file]
To remove keep only the .doc files:

remove-each file load %. [not suffix? ".doc"]
Here is an example of a block that uses multiple values:

blk: [
    1 "use it"
    2 "rebol"
    3 "great fun"
    4 "the amazing bol"
]

>> remove-each [num str] blk [even? num]
== [
    1 "use it"
    3 "great fun"]

>> remove-each [num str] blk [not find str "bol"]
== [
    2 "rebol"
    4 "the amazing bol"]
REMOVE-EACH also removes characters from a string:

>> str: "rebol is fun to use"

>> remove-each chr str [chr = #"e"]
== "rbol is fun to us"

>> remove-each chr str [find "uno " chr]
== "rblisfts"


2.5. ATTEMPT for Error Handling

The ATTEMPT function is a shortcut for the common REBOL idiom:

error? try [block]
The format for ATTEMPT is:

attempt [block]
ATTEMPT is useful in cases where you either do not care about the error result or you want to make simple types of decisions based on the error.

For example, you may want to create a directory, but you don't care if the function fails:

attempt [make-dir %fred]
Note that ATTEMPT returns the result of the block if an error did not occur. If an error did occur, a NONE is returned. For example, in the line:

value: attempt [load %data]
the value may be set to NONE if the %data file cannot be loaded (e.g. it's missing or contains an error). This allows you to write conditional code such as:

if not value: attempt [load %data] [alert "Problem"]
Or, even simpler:

value: any [attempt [load %data] 1234]
In this line, if the file cannot be loaded, then the value is set to 1234.


2.6. EXTRACT Function Updated

The EXTRACT function now includes an /INDEX refinement to allow you to specify what "column" you want to extract. For example:

data: [
    10 "fred" 1.2
    20 "bob" 2.3
    30 "ed" 4.5
]

>> probe extract/index data 3 2
== ["fred" "bob" "ed"]
If index is not supplied, then the first column is extracted.

In addition, the extract function has been fixed to properly extract blocks from a block series.


2.7. SAVE to Memory

The SAVE function can now write its results into memory. This is useful because the SAVE function contains formatting refinements that are found no where else.

To use SAVE to write to memory, specify a binary value rather than a file name. For example:

bin: make binary! 20000 ; (auto expands if necessary)

image: load %fred.gif

save/png bin image
Now the BIN binary holds the PNG formatted image. It was not necessary to write it to a file and read it back in.


2.8. SEND Refinements /Subject /Attach

The SEND function used for sending email has been extended to easily allow a subject line to be specified with a /SUBJECT refinement. This is a handy shortcut. For example:

letter: read %letter.txt

send/subject luke@rebol.com letter "Here it is!"
The above example will send the text of the letter with a subject line as specified. If the /SUBJECT refinement is not given, then the first line of the letter would be used as the subject.

In addition, the SEND function can now include attachment files by providing an /ATTACH refinement. A single file or multiple files can be attached. The specified files can be read from disk or can be provide as a filename with data. The formats are:

send/attach user letter file

send/attach user letter [file1 file2 ...]

send/attach user letter [[%filename data] ...]
You can also combine the formats.

send/attach user letter [%file1 [%filename data] ...]
Example attachments are:

user: luke@rebol.com
letter: read %letter.txt

send/attach user letter %example.r

send/attach user letter [%file1.txt %file2.jpg]

send/attach user letter compose/deep [
    [%options.txt (mold system/options)]
]


2.9. Difference for Date/time

The DIFFERENCE function will now provide the time difference (hours, minutes, seconds) between two date/time values.

>> difference now 1-jan-2000
== 20561:20:26
Normally, when you subtract date/time the result is the number of days, not time:

>> now - 1-jan-2000
== 856


2.10. System Port Added

The system port component was added. This component allows direct access to various OS-specific features. For example, the system port can catch Unix and Linux termination signals and perform a controlled shutdown. Under Win32, this port can be used to access win-messages.

More information about the System Port component will be provided as a separate document.


2.11. Interpreter Fixes

The following internal interpreter problems have been fixed.


2.12. Networking Fixes

The following fixes were made to networking:


2.13. Other Function Fixes

Fixes to natives and functions include:


Copyright REBOL Technologies. All Rights Reserved.
REBOL and the REBOL logo are trademarks of REBOL Technologies.
Formatted with REBOL Make-Doc 0.9.4.2 on 6-May-2002 at 20:33:13