Polymorphism in Rebol and Oz
Rebol and Oz are both languages in which it is the value that has the datatype, not the declared variable.
One Rebol motto is this:
words bind to values; the values have datatypes
Substitute ‘variable’ for ‘word’ and you have Oz
If a variable becomes bound – it is associated with a value – it can be handled as if it had the datatype of its value. Runtime determination of types is nothing new in Smalltalk or JavaScript, but this is different. In Rebol the variable, called a ‘word’, changes its type: it goes from being a set-word! which could be set to a value to being a word! with a value. In Oz this is a characteristic of a Prolog variable: free or bound (typed variables are found in at least two efficient Prolog implementations.) But Rebol also makes an interesting contrast with Strongtalk, which is like Smalltalk/Self but with optional types.
In Rebol it is possible to indicate which types a function may expect.
Take a function which acts like a ’set-multiple-values’ procedure
mult-val-proc: func ["demo returning values with datatypes" param1 [string! char! integer!]
/ret-int [integer!] /ret-char [char!] /ret-str [string!]] [
if ret-int [ return 42 ]
if ret-char [return param1 + #"*"]
if ret-str [return join param1 "*"]]
What this little piece of code is telling us it that it is a function which is declared to have one parameter and that one parameter could be a value of datatype string, integer or char.
The code introduced with ‘/’ are Rebol ‘refinements’.
If I call the function as
mult-val-proc/ret-int 21
then it is going to perform the code refinement and return 42.
Had I implemented the code as
if ret-int [ return param1 + 42 ]
then the call
mult-val-proc/ret-int #”*”
would return the character ‘J’
Had I implemented the code as
if ret-int [ return 42+ param1 ]
then the call
mult-val-proc/ret-int #”*”
would return integer 84
This permits tremendous flexibility that you might otherwise associate with Smalltalk and yet each of the refinements expects the correct type.
Problems arise if we pass a string when calling with /ret-int or /ret-char but we can pass either int or char into /ret-str. We can change the order of the join to
if ret-str [return join "*" param1]
and still we are ok. But we are vulnerable to a runtime errors if we pass in values of datatypes which cannot be added or joined to a series.
Something similar could be achieved in a typical imperative language with a kind of ‘C’ syntax with ‘overloading’ polymorphism declared as follows:
int func mult-var-proc(string param);
char func mult-var-proc(string param);
string func mult-var-proc(string param);
int func mult-var-proc(char param);
…
Of course if the three different types were sub-types of a common abstract type or implemented a common interface, everything becomes simpler but the types become obscured.
In ordinary Smalltalk our function would just be a method of the class Object testing the runtime type of its parameter or could be polymorphic in String and Magnitude and in that case also rely on polymorphism of our binary selector ‘+’.
The great thing about the declaration
param1 [string! char! integer!]
is that we see at a glance what we accept as arguments. The declared refinements
/ret-int [integer!] /ret-char [char!] /ret-str [string!]
indicate what we expect to return (but we must take responsibility in our code that we do return what is stated in our contract.)
What I can tell you is that it is a pleasure to work in if you come from Smalltalk or from a typed Prolog. The closest thing to this is Strongtalk. It has been said that Rebol is Self-meets-Tcl, but I think that it is more like O-meets-Tcl (as in someOfOz).
More than one major commercial project is known to be in Rebol; perhaps fewer than in Curl but likely more than in Oz. For all its marvelous flexibility, Oz is considered an academic language for research.
One thing I find odd is that while an Oz record is even more flexible that a Javascript Object, Oz is never discussed as a prototype-based language. Oz could easily have been design to mimic Self. It is neither based in objects or in classes. It is a multi-paradigm langauge for concurrency through dataflows. Rebol with dataflows (Liquid Rebol) takes one step closer to Oz. If you are trying out Reblets as browser applets, take the time to try out Oza-lets.
But if Rebol seems a bit more than you need for a web app, there is always Curl and the Surge RTE. If you have Windows PC and an evening to spare, download Strongtalk and see what it is like to be in a reST-ful state: the environment is the outline. Or is it vice-versa?