REBOL Programming/Language Features/Types
Generally datatypes are sets of values and some operations that can be performed with the values. The main purpose of knowing a datatype of a value is to know the operations we can perform with the value.
The following code is legal in REBOL:
>> x: 1 == 1 >> x: "2" == "2"
This property can be described by saying, that REBOL is a dynamically typed language. Some REBOL users describe it by saying, that datatypes are associated with REBOL values, not with variables.
The following code is illegal in REBOL:
>> x: 1 + "2" ** Script Error: Cannot use add on string! value ** Near: x: 1 + "2"
This is called type safety and is caused by the fact, that neither the integer value 1 nor the string "2" is automatically converted when the expression is evaluated.
Rich set of datatypes
REBOL has 45 basic datatypes to handle real world concepts like URLs, email addresses, telephone numbers, currency amounts. By stigmatizing each value with a value type, REBOL restricts the kinds of things that a program can do to values.
The richness facilitates the readability of REBOL scripts as well as block parsing as described elsewhere.
With the money! datatype, it is easy to do some basic accounting
>> AU$1.00 + AU$0.50 == AU$1.50
REBOL even ensures that we keep to the same currency
>> AU$1.00 + US$0.02 ** Script Error: AU$1.00 not same denomination as US$0.02 ** Near: AU$1.00 + US$0.02
Date calculations are as simple as
>> now - 1-Jan-2005 == 251
where now happens to be today's date of 9-Sep-2005.
Datatypes are also how we can specify that functions only take certain values. A function that expects to deal with files does not want to see an email! type of input.
print-file: func [ file [file!] ][ print read file ]
>> print-file email@example.com ** Script Error: print-file expected file argument of type: file ** Near: print-file firstname.lastname@example.org
The datatype safety means that REBOL protects us from mixing different types which might cause unexpected errors. However, we can specify that a function be polymorphic i.e. is able to accept more than one basic datatype for its argument.
type? is an example of a polymorphic function in that it will accept an argument of any datatype and yield its datatype as a result.
>> type? http://www.rebol.com == url!
Rebol datatypes can be divided to two groups: virtual datatypes and basic datatypes. Virtual datatypes are datatypes that serve as common "ancestors" for groups of basic datatypes.
|any-block!||block! path! set-path! lit-path! paren!|
|any-function!||function! native! action! op! routine!|
|any-string!||string! file! email! url! tag! binary! issue!|
|any-word!||word! set-word! get-word! refinement!|
|series!||any-block! any-string! list!|
|block!||[r e b o l]|
|struct!||#[struct!  ]|
As stated above, there is no implicit type conversion in REBOL, i.e. when we want to convert a value to a specific datatype, we have to do it explicitly and the conversion needs to be possible. This is how to convert a string to an integer:
>> to integer! "145" == 145
This rule seems to be contradicted by working code such as:
>> 1 + 2.0 == 3.0
which must have converted the integer 1 to a decimal before adding it to the decimal 2.0. However, the arguments are not converted by the REBOL interpreter before they get to the + operator. It is the + operator which is able to accept and convert that particular combination of types (integer and decimal) before doing its work and returning the result.
Generally the to function is the first function to consider when we are doing a type conversion. The type argument of the to function may be an example value instead of a datatype:
>> to 1 "145" == 145