Rebol2/R3-Alpha/Red have a notation for molding out objects:
Red>> obj: make object! [a: 10]
== make object! [
a: 10
]
Let's ignore for the moment the fact that it's giving a sequence of what looks to be two words and a block to denote a single OBJECT!. What it's trying to do is give you a syntax that looks like what it would take to create the object if typed from source. (Perhaps it would more appropriately be SOURCE OBJ vs. MOLD OBJ)
Little Objects with Big Problems
First, remember that Red's QUOTE is Ren-C's THE (give next item literally).
Now what if you said:
Red>> obj: make object! [g: quote (1 + 2) u: 0 unset 'u w: quote 'word n: none]
== make object! [
g: (1 + 2)
u: unset
w: 'word
n: none
]
The resulting MOLDing MAKE OBJECT! doesn't get close to what it's trying to capture.
-
In the original object G is a "PAREN!" with (1 + 2). Running that MAKE OBJECT! would give you G of INTEGER 3.
-
We'll assume it meant #[unset] instead of the word UNSET
-
To run as written, it would confusingly pass the UNSET function the next line as an argument. It would do
unset w: 'word
, thus unsetting word -
If it had said
u: #[unset]
instead, the make object! would have failed, as it's not legal to assign unsets via set-word in historical Rebol or Red.
-
-
W would come out as a WORD! here, instead of the LIT-WORD! in the original object.
-
N here might seem to work, but it only works so long as the word NONE is bound to #[none]. So round-tripping this field depends on the context you run the make object in.
Generalized escaping to the rescue
Ren-C doesn't have a full solution to the problem of round-trip representations as text. But now, when it comes to this, it's at least a powerful step closer.
>> obj: make object! [g: the (1 + 2) u: ~ w: the 'word n: null]
== make object! [
g: '(1 + 2)
u: ~
w: ''word
n: ~null~
]
Here we see these loopholes getting closed. The make is actually able to produce a structurally identical object (like I said, let's avoid talking about binding, that's its own conversation).
And reconstructing the object is context-independent...no keywords are being used. Note that I threw in a NULL for good measure, to show that there's a representation for that... a quasiform of the word "null"...that evaluates to the antiform of the word null.
The n: ~
is another quasiform... the quasiform of blank ("trash"), which evaluates to the antiform of blank, which represents the state of an unset variable (called "NOTHING"). Assignment of nothing to variables is legal so it wouldn't generate an error to run that (there is a state called NIHIL which is an empty pack isotope, which can't be assigned, but it's not legal to store in variables ever so no need to represent it here...though you could).
It's not necessary to put the apostrophe on all items, only those that evaluate...so the system should probably only add them if needed:
>> obj: make object! [i: 10 t: "hello" p: ''a/b/c]
== make object! [
i: 10
t: "hello"
p: ''a/b/c
]
INTEGER! and TEXT! can be left as-is, so perhaps worth it to do so. Here we see a "LIT-PATH!" (actually a quoted PATH!), escaped in the original representation for its assignment, escaped again for its re-representation.
This generalized-escaping-based mechanism replaces a previous attempt to deal with the issue, and gives strong evidence that the effort was time well spent.