2

Is it possible to access the global value of a variable that has been changed locally?

(setq foo 2)

(let ((foo 3))
  ;; can I access the original value here?
  )
Drew
  • 75,699
  • 9
  • 109
  • 225
Toothrot
  • 3,204
  • 1
  • 12
  • 30

2 Answers2

3

In addition to what @cyberbisson has said (no, you cannot) ...

First, in this:

(setq foo 2)

(let ((foo 3))
  ;; can I access the original value here?
  )

there is nothing that says that the (setq foo 2) sets the "global value" or the "original" value.

It depends on whether foo in that context is a special variable (aka dynamically scoped or global variable). For example, it could be a local variable, where this is the only context:

(let ((foo  42))
  (setq foo 2)
  (let ((foo 3)) ... )
  ...
  )

Second, there are not only global and local, and dynamic and lexical variables. There are also buffer-local variables (there used to also be frame-local variables, and you could still consider frame parameters to be such).

If you want to get the "global" value of a buffer-local value, that is, the default value for all buffers, then you can use function default-value to do so, and you can set the default value using setq-default:

(setq-default foo  42) ; Set the default value to 42, for all buffers.

foo ; ==> `foo' is 42 in the current buffer, unless it had been set otherwise.

(setq foo  3) ; Set `foo' to 3 in the current buffer.

(default-value foo) ; ==> Returns 42.

foo ; ==> `foo' is still 3 in the current buffer.

But maybe there is an XY problem lurking here? If so, please consider posing your "real" question separately - describe the problem you are trying to solve.

cyberbisson
  • 887
  • 1
  • 6
  • 17
Drew
  • 75,699
  • 9
  • 109
  • 225
  • I agree that OP is probably facing some issue we're not hearing the whole story about (XY Problem), _however,_ I think the question without context is still an interesting one to consider (I guess that's why you specified re-posting it as a separate question, and not simply editing). – cyberbisson May 08 '19 at 15:43
  • @cyberbisson: Yes, agreed. – Drew May 08 '19 at 18:01
1

The short answer is "no", there's really no means of escaping to a different scope like you might do in a language like C++.

There may be a very hacky way of getting to the variable if you use dynamic binding, although you should definitely not try it (I have not). From Dynamic Binding - GNU Emacs Lisp Reference Manual:

Dynamic binding is implemented in Emacs Lisp in a simple way. Each symbol has a value cell, which specifies its current dynamic value (or absence of value). [...] When a symbol is given a dynamic local binding, Emacs records the contents of the value cell (or absence thereof) in a stack, and stores the new local value in the value cell. When the binding construct finishes executing, Emacs pops the old value off the stack, and puts it in the value cell.

So you could look up this internal structure, and surf around the stack of variables until you reach the level you want. Don't do this! :) Instead, you might consider either binding your global variable to a different name, or renaming the variable you have locally so it doesn't collide.

As an aside, this is one of the reasons that Scheme and Lisp differ in their syntax. In Lisp, functions and variables exist in different namespaces, but in Scheme, they exist in the same one, so you could even cover up a function's definition with a local variable of the same name.

cyberbisson
  • 887
  • 1
  • 6
  • 17
  • What do you mean they differ in their syntax? Handling of namespaces does not belong not belong to syntax, does it? – JeanPierre May 08 '19 at 16:08
  • Thanks for your question. I was mainly referring to the _byproduct_ of those namespaces being syntactic differences like `defun` vs. `def` and `funcall` vs. no special handling for Lisp vs. Scheme (respectively). – cyberbisson May 08 '19 at 16:39