7

I know we have defvar and setq. defvar has a special meaning on defining global variables because the assignment only happens once. So I was thinking about use setq to get the desired behavior of defparameter from Common Lisp. However when I use setq without defvar (as replacement) I got a warning: reference to free-variable.

I saw on the table of hyperpolyglot lisp global-var section which relates defparameter with setq and set, so seems this is common. But I'm still wondering about the warnings...

There is another alternative to declare global variables as defparameter does? (declare and can change calling again)

JeanPierre
  • 7,323
  • 1
  • 18
  • 37
Manoel Vilela
  • 675
  • 3
  • 20
  • 1
    It's not nearly as big of a problem in practice that `defvar` doesn't reset the variable when loading lisp code, you can `C-M-x` on the form to reset it manually. – wasamasa Sep 05 '17 at 16:18

3 Answers3

7

Not as far as I can tell, no.

I've always questioned the usefulness of having both defvar and defparameter in Common Lisp. If you don't mind, leave a comment explaining why having both forms is useful - I'm honestly interested to know. I know what they do, I just don't know why the difference is important enough for both forms to be in the standard.

Anyway, here's a macro that works for me:

(defmacro defparameter (var value &optional docstring)
  `(if (boundp ',var)
       (setq ,var ,value)
     (defvar ,var ,value ,docstring)))

That's my first defmacro, so feel free to offer improvements. I'm normally a scheme guy.

Manoel Vilela
  • 675
  • 3
  • 20
Jeff Spaulding
  • 484
  • 2
  • 6
  • Where do I put my documentation ? – politza Sep 06 '17 at 11:17
  • Right after the parameter list, like a regular Emacs function. Try doing `M-x find-function` and finding the source for something like `when` or `dolist` for examples. – Jeff Spaulding Sep 06 '17 at 18:05
  • I was thinking... `setq-default` would not do exactly what I want? At least when I tested worked as I expected without warnings. – Manoel Vilela Sep 10 '17 at 08:06
  • About usefulness of both forms on Common Lisp, this is something I have my doubts too. `defvar` can avoid the problem of reload file or calling again of some function. Let say we want declare (defvar counter 0) inside of a function as similar of static of C, but is bad calling again as it because will erase our counter. `defparameter`, in another hand, ensure that the value is setted with dynamic-binding and resetted (if was declared previously). Actually, I always wondered why have so much ways to assign variables (setq, setf, setv, set, defvar, defparameter) in CL... but too late to ask. – Manoel Vilela Sep 10 '17 at 08:37
  • I like in general use `defparameter` instead `defvar` to declare global variables in CL. This avoid problems on development with emacs and the need to manually reset variables — is painful sometimes. Because if you are changing the code a lot, and you have really much code, the better way is just restart the REPL. But using defparameter you just re-eval the buffer. BTW, at least reading the code of community, defparameter is a common practice. I only see defvar used when that line of code have the intention to be executed again and we don't want to change the value when this happens in anyway. – Manoel Vilela Sep 10 '17 at 08:44
  • I think politza was suggesting to change your code to `(defmacro defparameter (var value documentation) ...)` – npostavs Sep 10 '17 at 19:03
  • Probably yes, @npostavs. It's worth to remember that defparameter can have the optional documentation string. In that case `(defmacro defparameter (var value &optional doc) ...)` will do the job. – Manoel Vilela Sep 11 '17 at 01:12
  • Of course since you attach the documentation string to `defvar` inside of the macro. From SBCL: DEFPARAMETER names a macro: Lambda-list: (VAR VAL &OPTIONAL (DOC)) – Manoel Vilela Sep 11 '17 at 01:17
6

In Emacs Lisp, defconst doesn't actually enforce constness, and therefore works pretty much like Common Lisp's defparameter:

  • it unconditionally sets the variable;
  • it marks it as special;
  • it avoids any warnings due to setting unbound variables.
jch
  • 5,680
  • 22
  • 39
  • 1
    Great to know!!! You could describe the difference between the usage of `setq-default` compared to `defconst`? – Manoel Vilela Oct 03 '17 at 21:26
  • 2
    If a variable is buffer-local, `setq-default` sets the default value, while `setq` and `defconst` set the local value. So they're completely different. Don't use `setq-default` unless you understand what it does. – jch Oct 03 '17 at 23:38
1

This version of defparameter in elisp tries to be a bit tighter - requiring the name to be a non-nil symbol, the documentation if present to be a string, and ensuring that the initial-value form is not evaluated more than once (in case it has side-effects).

(defmacro defparameter (name &optional initial-value documentation)
  "Like `cl-defvar', but unconditionally sets the named variable to the evaluation of the `initial-value' form."
  (assert (and name (symbolp name)) t "Name must be a non-nil symbol")
  (assert (or (not documentation) (stringp documentation)) t "Documentation if passed must be a string")
  (let ((value-sym (cl-gensym "value")))
    `(let ((,value-sym ,initial-value))
       (cond
         ((boundp ',name)
          (setq ,name ,value-sym)
          ,@(and documentation `((put ',name 'variable-documentation ,documentation)))
          ',name)
         (t
          (defvar ,name ,value-sym ,@(and documentation `(,documentation))))))))
spacebat
  • 11
  • 2