@wolframkriesing liked my last article (thanks!) and was interested in the code is data claim. I take this for granted, so it’s bit hard for me to write about it, because I don’t have some point where to end my article. So it’s going to be a mess probably.
When you write some code, it’s a string!. That’s same in basically all languages, I guess (unless you have to punch some paper cards or something). Let’s show some example of this, simple plusone function, that returns input plus one:
red>> source: "plusone: func [value] [value + 1]"
== "plusone: func [value] [value + 1]"
red>> type? source
== string!So now we have source string!. To turn this string into something, that Red understands, we have to load it:
red>> code: load string
== [plusone: func [value] [value + 1]]load parses the string and turns it into Red values. We still do not have our plusone function. We just have a block! of values. This is really important, load just tries to load string into memory and turn it into Red values. It does not run anything. Let’s check it:
red>> plusone
*** Script Error: plusone has no value
*** Where: catchSee? Red still does not now about plusone function. We have to do the block:
red>> do code
== func [value][value + 1]
red>> type? :plusone
== function!So now we have our plusone function available. To sumarize this:
load turns source string into data that Red can understanddo can run that dataLet’s try to write our function in some other language, for example Javascript (because it’s everywhere). In Javascript, we have eval that can turn our source into code:
> source = "plusone = function (value) {value + 1}"
'plusone = function (value) {value + 1}'
> plusone(1)
ReferenceError: plusone is not definedWe have our source, plusone is not a function yet, so we can use eval now:
> eval(source)
[Function: plusone]
> plusone(1)
2Here’s the important difference between Red and Javascript: eval directly runs the source. The source is not loaded and turned into data. Now back to Red to show you, why it’s important:
red>> foreach value code [print [type? value mold value]]
set-word plusone:
word func
block [value]
block [value + 1]As you can see, our code block holds four values. set-word!, word! and two block!s. Every value in Red has it’s datatype. Javascript’s {value + 1} may look almost same as Red’s [value + 1], but they are vastly different. Because in Red it’s all data, it’s very easy to manipulate it. I am not going to use plusone function here, but something simpler, so it will be easier to understand. So define something really simple:
red>> code: [1 + 1]
== [1 + 1]
red>> length? code
== 3Now we run that code:
red>> do code
== 2Runs as expected. Let’s change first value to some different number:
red>> code/1: 5
== 5
red>> code
== [5 + 1]
red>> do code
== 6Can we also change the operator? Of course we can!
red>> code/2: '-
== -
red>> code
== [5 - 1]
red>> do code
== 4We must use so called lit-word! here ('- instead of -), so the minus is not evaluated.
And now append something to our code:
red>> append code [+ 3]
== [5 - 1 + 3]
red>> do code
== 7I mentioned that we must prevent - from evaluation. What does that mean? Until it gets evaluated, - is just a word. It must be evaluated, to get its value, the minus operation:
red>> type? second code
== word!
red>> type? get second code
== op!get gets word’s value and op! is operator datatype. So unless you evaluate the code, it’s just data. And of course, it’s possible to change word’s value:
red>> code: [1 + 1]
== [1 + 1]
red>> do code
== 2
red>> +: :-
== make op! [[
"Returns the difference between two values"
v...
red>> code
== [1 + 1]
red>> do code
== 0Isn’t it funny? I think it is. Dangerous, yes, but funny. So I hope that this explains a bit what does it mean, that code is data.