What's the purpose of #[datatype] constructor in Rebol

264 Views Asked by At

I just came across this syntax in Rebol to construct some values:

>> #[email! "[email protected]"]
== [email protected]

This seems to be equivalent to

>> to email! "[email protected]"
== [email protected]

and this

>> #[string! "hello"]
== "hello"

While these error out:

>> #[integer! 1]
** Syntax Error: Invalid construct -- #[
** Near: (line 1) #[integer! 1]
>> #[decimal! 1]
** Syntax Error: Invalid construct -- #[
** Near: (line 1) #[decimal! 1]
>> #[string! 1] 
== [string! 1]

I wonder what's this for? what benefits does it bring?

1

There are 1 best solutions below

0
On BEST ANSWER

This syntactic structure is called "construction syntax" (also see CureCode issue #1955). Its raison d'être is to allow literal forms for values which could not otherwise be directly represented.

There are two main classes of situations that require construction syntax.

  1. Values which (except for construction syntax) have no separate lexical form, but are only constructed through evaluation.
  2. Values with a regular literal form, but where a particular value is "special" in as far as the value no longer can be written directly.

(1) Construction Syntax for Direct Value Representation

One prominent example for this class is object!. Rebol objects are typically created with code such as make object! [a: 42]. This is not a direct literal representation of the resulting object value, but rather code which, when evaluated, (in the DO dialect) creates the expected object value. Construction syntax allows for a direct representation of the value: #[object! [a: 42]].

Other typical examples are #[none!] and the somewhat irregular (construction-syntax-wise) #[true] and #[false] (note the missing !). Wrapping one's head around the difference between e.g. #[none!] and none will lead to a deeper understanding of Rebol semantics (and is thus left as an exercise for the reader).

(2) Construction Syntax as "Escape Mechanism"

A typical example for this case is a reversed URL, such as the value you get from reverse http://stackoverflow.com. If the resulting value would be serialised as a plain URL!, the serialised form will no longer be syntactically valid:

>> /moc.wolfrevokcats//:ptth
** Script error: // does not allow unset! for its value2 argument

Construction syntax provides an escape mechanism for this situation:

>> #[url! "/moc.wolfrevokcats//:ptth"] = reverse http://stackoverflow.com/
== true

This particular example also points to a problematic situation:

>> reverse http://stackoverflow.com/
== /moc.wolfrevokcats//:ptth

Arguably, this output (produced by the mold native) is wrong: the result as displayed is not a valid lexical representation of the corresponding value.

There's a few bugs tracking particular instances of this class of problems (such as CureCode issue #2010 for URL!). One proposal on the table towards a more general solution is to have a round-trip check built into some variant of MOLD: whenever LOAD-ing the result of a non-construction-syntax MOLD results in value different from the original value, this MOLD variant would fall back to serialising to construction syntax.