5
SEP
2009

Self-Modifying Fun

An interesting consequence of code being data in REBOL is that it is very easy to modify code on the fly. You can write code that writes code. It's like in the Terminator movies where machines build machines, except that using REBOL probably won't result in judgement day. I hope!

You can use some of the series functions on instances of the function type as well. If you want to access the body of a function you get the second value of the object. Let me illustrate:

f: func [] [print "I am a function"]

The first block is the parameter block and since this function does not take any parameters as input, it is empty. The second block is the body of the function and it contains the code to print the string "I am a function".

So, let's examine the body of the function by getting the second element of the function instance series. Note that >> is the interactive REBOL prompt and == is the result of whatever operation you execute at the prompt.

>> second :f
== [print "I am a function"]

The : character is used to retrieve the value that f is bound to without executing the function. Calling the function yields the following expected result:

>> f
I am a function

OK, let's modify it to print something else.

>> poke second :f 2 "I am a modified function"
== "I am a modified function"

Poke replaces a value in a series with another value at a given index. In the example above, the value at index 2 in the body of the function is replaced with the value "I am a modified function". Since REBOL uses 1-based indexing, the value at index 2 was previously "I am a function". So let's check the source of the function now.

>> source f
f: func [] [print "I am a modified function"]

It seems like the modification worked. Calling the function yields the following result:

>> f
I am a modified function

Being able to modify code like this on the fly is a powerful feature. But, like Spider-Man's uncle Ben used to say: "With great power comes great responsibility". It is very easy to produce self-modifying code that is downright weird. Here is an example:

f: func [:g] [append second :g [+ 1] 1]

What does this function do? It takes a function as a parameter and adds + 1 at the end of the body of that function and then returns 1. There is nothing keeping us from passing the function f as a parameter to itself, so let's see what happens if we do. The : in the parameter specification suppresses evaluation of the parameter, so we can pass in the word bound to the function f instead of getting its value like we'd do with second :f. Here we go:

>> f f
1
>> f f
2
>> f f
3
>> source f
f: func [:g] [append second :g [+ 1] return 1 + 1 + 1 + 1]

Each call to the function modified the function itself, so the returned value was incremented with one everytime. There's no counter variable or anything, we simply added the code for + 1 to the function each time.


About This Site

Hello, my name is Martin Johannesson and this is my home on the web. I live in Stockholm, Sweden, where I work as a software engineer at a software company.

Ever since I was a kid and discovered the art of programming on my C64, I've been tinkering with my own little software projects and experiments. This site is one such experiment.
more...

Recent Entries RSS Feed

Tags

Amiga blog C game GLGX GLSL iPad iPhone Java jQuery OpenAL OpenGL Programming REBOL Shaders Vertex Shader web

Blog Archive

2010: 01 02 03 04 05 06 07 08 09 10 11 12
2009: 01 02 03 04 05 06 07 08 09 10 11 12

Random Images Load new images

loading
loading
loading
loading
loading
loading
loading
loading
loading
loading
loading
loading

People I Know