I have backgrounds in both rebol and python - which compare I suppose -
as do common lisp and newlisp in terms of scoping rules.
Be that as it may - I've seen arguments ad naseum about dynamic vs lexical
scoping - but what I'm really interested in how to use newlisp scoping to
my advantage.
I find that I've been using 'let a lot - and maybe more than I should.
So I would welcome comments, caveats, rules of thumb, etc on how
to take advantage of dynamic scoping. I've not used 'local at all.
Would be great to see further comment on that function - there's not a
lot about it in the manual.
Thanks
Tim
There's a post at Jeff's old site //http://artfulcode.nfshost.com/files/why-not-dynamic-scope.html#unique-entry-id-25. It's all good reading... And some discussion on this forum in places - //http://www.alh.net/newlisp/phpbb/viewtopic.php?t=1657.
I don't feel able to say wise things about the subject. But I like using local for when I don't know what the value's going to be for a symbol when the function begins - why waste time setting it to empty when you can get it done for you, and I don't see what's wrong with using let a lot. Some people like doing all the work in a letn definition block. My simple rule of thumb (not yet posted to //http://rulesofthumb.org/ :)) is to make sure that I know where symbols are defined before I refer to them; either they're in the function's argument list, in the let or local list, or they've got asterisks around them and are global...
let-binding is used quite a bit in most lisp-like languages, as well as ocaml. It is nicer than assignment expressions because it explicitly declares a variable to be local to the block.
Dynamic scoping and let-binding are different ballparks. Let-binding is a local binding to a block, as opposed to global bindings that set/setq perform.
Dynamic scoping simply means that a variable's value is its value in the current scope. If you call f() from g(), and a = 10 in g(), then it will equal 10 in f() as well (unless f() uses let-binding to shadow a).
Lexical scoping means that the program is analyzed lexically and functions lookup variables in the environment in which they were defined, rather than in which they were executed.
So, if f() is called from g(), and a=10 in g(), then the value of a may not even be visible to f(), because f() only knows about variables in its own environment.
Let binding has more to do with local/global scope than dynamic/static.
Jeff, I'm familiar with let from elisp and rebol (only rebol calls it 'use).
I think that I understand the issues of scoping - and I have bookmarked
what you've written about the issue.
I am just "fishing" - no, no, not trolling :-)
for some tips that will help me to take advantage of dynamic scoping.
For instance in rebol I try to use naming conventions, like *globalvar1*,
*globalvar2*, etc.... since rebol allows asterisks as legitimate symbol name
components.
Thanks!
Tim
As well as - or instead of - the asterisk, you can use contexts. This is Lutz' suggestion:
Quote from: "Lutz"
Just put all globals in its own context 'global' or 'gl' or even shortening to capital 'G' for those who hate typing (like myself ;-))
(set 'G:database "/usr/home/joe/data/database.lsp")
(set 'G:n-config 12345)
A context qualified variable is global by definition, because contexts names are global. It also keeps all globals together in one place for inspection or serializing with
(save "appglobals.lsp" 'G)
The `save` command is useful with dynamic scope. It is much like a continuation - you are saving something similar to the current stack frame. You lose shadowed variables, though:
(set 'a "bar")
(let ((a "foo")) (save "foo.lsp"))
That will save `(set 'a "foo")` to foo.lsp. I use this as a way to preserve state in cgi applications using sessions. I give the client a unique id and store it in a cookie with a time stamp. If the user opens another page, I can restore all variables by loading the file - (load (string 'session-id ".lsp")).
In a persistent process, you can do tricks like saving the state a location A and then, if something fails afterward, reloading it later:
(save "temp.lsp")
(unless (catch (do-something-risky) 'result) (load "temp.lsp"))
Thanks folks. You're talking about methods that I am very familiar with
in rebol!
BTW: rebol has a poorly documented feature that I use a lot and is IMHO
very valuable:
An anonymous context wrapping a function which is made global by
the
set 'function func
syntax. "words" declared inside of
the context or the function body are total private as far as I can tell,
and are pesistent (continuations)
example:
context[set 'f func[][m: 1]]
Could 'let or 'local be used at the top level with a function defined within
made global similarly?
The following:
(let (f) (define(f) println "here"))
doesn't seem to 'export' 'f
- Oh, I know about the default functor - very handy, I think.
tim
No. You mean closures, not continuations. You can do that with a context functor:
(define (foo:foo) (println bar))
(setq foo:bar "Tim")
(foo) ; => prints Tim
You're correct. My typo. Additionally:
I've had just a couple minutes to play with
'save and it looks like it is more flexible and a bit different from
rebol/save. In fact since my bread-and-butter is CGI, it's going to
_extremely_ valuable for me.
Thanks for the introduction.
Tim