Question

Update: If I have a few functions that I want to mutate a global variable that is passed as a function argument, some can do this by passing just the symbol of the global (as in the case of pushing something onto part of a list), but other functions will require that the symbol be quoted when it is passed so I can access the symbol-value and mutate the outside variable, required for using setq in a function. This question is basically about creating a consistent interface for a user of these functions without confusing them that sometimes you pass the symbol, othertimes you pass the quoted symbol

Example way to streamline the interface for a bunch of functions, by using a helper that has the same usage reqardless of how the mutating function works:

Here are 2 basic examples of my technique:

(defun push-something (global something)
  (push something global)
  global) ;; not necessary to return it here since the 
          ;; preceding line already does, but doing so 
          ;; for consistency with other functions and clarity

(defun push-cdr (global something)
  (push something (cdr global))
  global) ;; must return it if I am going to set the 
          ;; dynamic var to the result of this function, 
          ;; because the preceding line doesn't return the 
          ;; entire new result of the variable

;;; "dirty" function for mutating global variable using "clean" functions above:

(defun set-global (fn global &rest values)
  (setf (symbol-value global) (apply fn (copy-list (eval global)) values)))

In this last one, I must eval the global since it is quoted for use with symbol-value and then I copy-list so that global isn't directly mutated accidentally by whatever fn I choose (as would be the case with push-cdr which might be non-trivial in more complicated functions).

Output:

CL-USER> (defparameter *g2* nil)
*G2*
CL-USER> (set-global #'push-something '*g2* 5)
(5)
CL-USER> *g2*
(5)
CL-USER> (set-global #'push-cdr '*g2* 99)
(5 99)
CL-USER> *g2*
(5 99)

...and the same functions could be used with *g1* or *g3* etc all through the access function set-global.

Is this good or bad style, or am I missing a much better way to achieve this functionality?

Was it helpful?

Solution 2

Why don't you get rid of set-global function entirely, and if you want all your function to have the same style of passing in the global variable, just make them all use symbol-value so anyone using these functions won't need to know which do and which do not require a quote in front of the global variable name getting passed. Much easier right?

OTHER TIPS

This is a bad style and a waste of your time.

  1. push-something is equivalent to cons.

  2. push-cdr is not functional: it modifies the argument in-place or fails with an error on nil argument.

If you want to change the value of the global variable, then using setf explicitly is much clearer.

If you want to modify the internals of a global value in some intricate way, you may need to write a special function for that - but that function should be agnostic of the fact that it is modifying the value bound to a global variable as opposed to a lexical variable.

In short, there are two separate orthogonal issues - changing a global variable (use setq) and changing internals of an object (be agnostic of its global nature).

PS. I am not sure what you mean by "setf does not change the value of a global variable when it's inside the function", but:

(defvar *foo* 10)
*FOO* ==> 10
(defun change-foo (x) (setq *foo* x))
(change-foo 123)
*foo* ==> 123
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top