One step closer to closures, or, how I captured variables by clever use of context switches.
Randall Reetz
randall at randallreetz.com
Sat Aug 30 15:23:59 EDT 2008
Just want ti be clear about my previous post. The main point is that the whole thing can be turned off and on globally. Also, when it is globally on, only those objects that had their own individual sendchanges property turned on (defaulf: false) would be effected. The interesting thing here is that properties and vars are treated as objects in their own right. Context (what got changed, what it is now and what it was, when, by who) is then just a way of querying instance (calls and inheritance) as a composite data structure. In my example, the messages are concatinations of the property or variable name with the "_changed" suffix (should it be a prefix?). The scriptor can write code that writes on-the-fly handlers that can be dynamically inserted and removed from the message passing hierarchy as needed.
Of courrse the syntax could be shortened to just the prop or var name...
on myVar
or
on height
put line 1 of the context into parentObject
end height
Randall
-----Original Message-----
From: "Randall Reetz" <randall at randallreetz.com>
To: "How to use Revolution" <use-revolution at lists.runrev.com>
Sent: 8/29/2008 10:14 AM
Subject: RE: One step closer to closures, or, how I captured variables by clever use of context switches.
Cool! What i havw always argued for is a global property that turned on or off the behavior that the changing of any var or property generated a message. The message would only happen if a property "sharechanges" of all vars and props (by default false) was set to true. The message would be sent with context and old value parameters.
on rect_changed, context, oldval
Storecontexthistory
Bla bla bla
End rect_changed
randall
-----Original Message-----
From: "Andre Garzia" <andre at andregarzia.com>
To: "How to use Revolution" <use-revolution at lists.runrev.com>
Sent: 8/29/2008 1:55 AM
Subject: One step closer to closures, or, how I captured variables by clever use of context switches.
Folks,
This is the kind of post you get when I keep code until 5:15 AM. Today
I've set a goal to produce a library that would allow me to create
persistent variables, by persistent variables I mean that when the
program finishes it somehow saves the variable contents and when it
loads, it inserts the content back. I know about custom properties,
SQL Databases, stack files, that's how we usually solve this kind of
issue, but I'd decided to try something different and work with actual
variables.
To solve this problem, I've decomposed the task into two big
components, the saver and the loader. The loader is the piece of code
that picks the value and inserts back into the variable, this is
trivial, you just read the value from somewhere and insert it back,
the tricky thing is the saver.
Picking values from global variables is easy, you just declare a
global and grab the value. Script local variables are easy to access
when you're in the same script. Temporary variables, well, those are
tricky to grab when you're not in the same handler as them. So the big
task is, how to we access variables that were defined and used in a
different context? For those new to transcript let me put a simple
example below:
on firstHandler
local temp
put "I am a happy variable" into temp
end firstHandler
No code outside "firstHandler" can query the value of the temp
variable, it is defined in the context of that handler. Now, imagine
that you have the following piece:
on firstHandler
local temp
put "I am a happy variable" into temp
newPersistentVariable "temp"
put "I've just changed the value of temp." into temp
secondHandler
end firstHandler
on secondHandler
put captureVariable("temp")
end secondHandler
And when secondHandler runs, it outputs "I've just changed the value
of temp.". If you look carefully at the code above, you'll see that
this is not an easy task. We have a strange handler called
newPersistentVariable which we don't know what it is and on the
secondHandler we have a function that is supposed to return the value
from a variable on the other handler.
Now, even without the details about those two functions, you can see
that we're redefining the content of the temp variable after calling
newPersistentVariable, so in a magic way, captureVariable function is
returning the last value of temp .
How does it works? It works by capturing the context and switching to
it when needed. When newPersistentVariable is called it receives a
param which is the variable name that you want to keep track (not it's
value). newPersistentVariable then checks the executioncontexts and
save it for later reference. When we call captureVariable() we pass
it a variable name, it then checks to see in which context that
variable was defined, it switch there and with a little hack, picks
the value from there.
The code for both functions is:
local lPersistentVariablesA
global gVar
function captureVariable pVariable
put lPersistentVariablesA[pVariable] into tContextsRaw
put 0 into tNum
repeat for each line tLine in tContextsRaw
add 1 to tNum
put return & tNum & comma & tLine after tBuf
end repeat
delete char 1 of tBuf
set the cREVScriptDebugMode of stack "revPreferences" to true
set the debugcontext to (item 1 of line -2 of tBuf)
put format("global gVar; put %s into gVar", pVariable) into tCmd
debugdo tCmd
set the debugcontext to empty
set the cREVScriptDebugMode of stack "revPreferences" to false
return gVar
end captureVariable
on newPersistentVariable pVariable
put the executioncontexts into lPersistentVariablesA[pVariable]
end newPersistentVariable
Now, why this is useful? Well, as you can see from the code, we have
an array called lPersistentVariablesA, we could simply loop the keys
of that array and capture and save all variables on shutdownRequest.
We could modify the newPersistentVariable to check for the saved
content and insert it back.
Whats wrong with my current code? (A-Ha!) Right now, if you nest to
many handlers, the context switch fails somehow... it's hard to debug
this. I think that as Rev exits the handlers it drops the contexts
(can we call that backtracking?). So if we go from firstHandler into
secondHandler into thirdHandler, then in the thirdHandler we can
capture variables from them all, but if we go from firstHandler into
secondHandler out of secondHandler and into thirdHandler, then
anything from secondHandler is lost.
Anyway, it still a nice hack and it still useful. I've developed this
to use with CGI programming, and in CGIs most things happen in the
startup script or very near it, so I can still use these routines to
pick variables from contexts that I know are still alive.
How to solve this? Well, I don't know, I just wanted to play and try
to build myself something that would allow me to freeze the execution
contexts in time so that I could re-use them later (still trying to
create state out of the stateless nature of cgis, order from
chaos...).
Andre
--
http://www.andregarzia.com All We Do Is Code.
_______________________________________________
use-revolution mailing list
use-revolution at lists.runrev.com
Please visit this url to subscribe, unsubscribe and manage your subscription preferences:
http://lists.runrev.com/mailman/listinfo/use-revolution
_______________________________________________
use-revolution mailing list
use-revolution at lists.runrev.com
Please visit this url to subscribe, unsubscribe and manage your subscription preferences:
http://lists.runrev.com/mailman/listinfo/use-revolution
More information about the use-livecode
mailing list