From: Pascal J. B. <pj...@in...> - 2012-04-25 19:41:23
|
"Yves S. Garret" <you...@gm...> writes: > I wouldn't say I "worry" about it. The concept of not having global > vars at all (well, unless there's a damn good reason, avoid at all > costs like the 'goto') has been drilled down into my skull ever since > I finished my first C++ programming class in college. > > From a design perspective, this makes sense. Fewer global vars are a > good thing. They can give you quirky behavior unless you're super > careful. I was more curious when you guys design Lisp apps, how you > treat global variables (yes, classes, functions, etc. are global as > well, but this is not exactly the same thing) in Lisp. Even in > imperative and OO languages globals have a time and place (but very > seldom and there has to be a damn good reason why). Do professional > Lisp developers actively embrace them? Stay away from them like you > would in other programming languages? Or is there some other > middle-ground that I'm not aware of. > > The example that you provide is exactly where I could see how things > could go very wrong in terms of undefined behavior :-) . How are > global variable regarded in Lisp? I reiterate, there's no dogmatism. They're a tool, and as any tool, they can be put to good use, or to bad use. But I repeat, one good use is that they allow easy access to data from the REPL. You can store some data from the inners of a function to a global variable, so that when it's done you can inspect that data from the REPL: (defvar *data*) (defun f (n p) (push p *data*) (if (zerop n) p (f (1- n) (* n p)))) (f 14 1) --> 87178291200 *data* --> (87178291200 87178291200 43589145600 14529715200 3632428800 726485760 121080960 17297280 2162160 240240 24024 2184 182 14 1) This goes also for dynamic binding. While it would be in general better to use dynamic binding, ie.: (defun f () (let ((*global* local-value)) (g))) for debugging purposes it may be good to use: (defun f () (setf *global* local-value) (g)) So that when f is ran, you can call and debug independently g (or h or other inner functions), with *global* bound to local-value. When debugging is done, you revert to the dynamic binding LET so that F doesn't change its global binding. Notice how dynamic binding actually mitigates the globalness of the variable. (defvar *global* '()) (defun g () (print *global*)) (defun f () (let ((*global* (cons 42 *global*))) (g)) (values)) (f) *global* --> () with a dynamic binding LET, the global value of the *global* variable is not changed, just masked temporarily. This is important also with threads, where one can give a set of dynamic bindings which will be local to the thread. -- __Pascal Bourguignon__ http://www.informatimago.com/ A bad day in () is better than a good day in {}. |