Thanks to Joe Marshall for his extremely helpful explanation
of Rebol 1 vs. Rebol 2 and contexts and GC.
>> make-adder: func [x][func[y][+ x y]]
>> add6: make-adder 6
>> add6 1
== 7
>> add5: make-adder 5
>> add5 1
== 6
>> add6 1
== 6
>> source add6
add6: func [y][+ x y]
OK, this is the "problem", as we all know. We wish add6 1 still returned 7.
We are told that each function has its own context.
Well, I thought that might mean that add6 having it's own
context would be fine. But the problem I guess is that
add6 just gets a pointer to the function func[y][+ x y]
that is created once only when make-adder's definition is first evaluated.
And add5 gets another pointer to the same function instance.
I am not sure if add5 and add6 have a context, because they
are just words that point to the actual function, not functions themselves!
Clear? Dizzy? Have an aspirin.
>> make-adder: func [x][print "stuff changed" func[y][+ x y]]
>> source add6
add6: func [y][+ x y]
>> add6 1
== 6
>> add5 1
== 6
So, re-defining make-adder makes no difference now.
add6 and add5 still have a pointer to the original func instance and
there's still only one and it has only one context.
I finally figured out what Joe Marshall meant by "free variable".
in our function func[y][+ x y] it is x that is the free variable,
because it is not a parameter nor a local variable, so it must
be resolved beyond the local function.
Usually vars not local are resolved to a global variable, but in this
case the dynamic, "unpredictable" extent of Rebol 2 leaves x
resolving to a function's context that make-adder can still fool with
upon it's next use.
I thought if I could get another instance of the function it could
have it's own context and be safe from further changes by make-adder,
but look, this doesn't work and I don't know of any way to fake it:
>> make-adder: func [x][copy func [y][+ x y]]
>> add6: make-adder 6
** Script Error: copy expected value argument of type: series port bitset.
** Where: copy func [y] [+ x y]
this didn't work, either:
>> make-adder: func[x] [do [func [y] [+ x y]]]
nor this:
>> make-adder: func[x] compose [func [y] [+ x y]]
So, is there a clever way to get it to cough up another instance
of the function with it's own context that won't get changed by running
make-adder again?
I guess I don't even care if the GC still ruins
it because I assume that will actually get fixed, silly me.
Thanks!
-galt
p.s. More thoughts on the matter:
Frankly, being able to treat functions in special flexible ways
was one of the things that most attracted me to Rebol.
There are lots of other good things about Rebol, too, but losing
first class functions/continuations does impact your possibilities,
for sure.
Just recently I heard an interview (on the web) with the new guy they got at
rebol
(sorry, I am bad with names sometimes) who is heading up the company
bragging about rebol having first-class continuations,
It seems like he's using old sources of info. If the first class
stuff is broken and doomed, he should stop referring to it.
Of course he probably has no idea what a first-class continuation is,
most people don't.
Where is Rebol going to go now?
They are going to have to change something,
because its a lame design now. They should
either figure out a way to get their first class contexts back,
or else abandon contexts entirely. This half-way stuff is
not really desirable. And if contexts are gone, then
we can stop getting confused by examples from Rebol 1 days
when they were something you would want to actually use.
With the current design you should try to avoid them
and anything that depends on them.
With so many C-programmers at Rebol, it's likely Rebol
will continue to become more c-like by the day, I suppose.
-galt