5

I want to define a trash directory in my user-init-file but I don't know which way to do this is best or most correct. I currently have something like this:

(defvar my-trash-dir
  (expand-file-name ".trash" user-emacs-directory))
(if (not (file-exists-p my-trash-dir))
    (make-directory my-trash-dir))
(setq trash-directory my-trash-dir)

Is this correct? Is there a better way to do this, maybe by using setq or defconst?

Basil
  • 12,019
  • 43
  • 69
rchar01
  • 437
  • 4
  • 8
  • See also [`(eintr) defvar`](https://www.gnu.org/software/emacs/manual/html_node/eintr/defvar.html) and https://emacs.stackexchange.com/q/29710/15748. I'm not flagging this question as a duplicate of the latter because it is more focussed on which form is more idiomatic. – Basil Jan 23 '18 at 11:02

3 Answers3

9

If the sole purpose of defining my-trash-dir is to use its value to set the user option trash-directory, then you should just write

(setq trash-directory (expand-file-name ".trash" user-emacs-directory))

or (if you don't mind wasting a millisecond or two at startup) even

(setq trash-directory (locate-user-emacs-file ".trash"))

This is because trash-directory is automatically created for you when the command move-file-to-trash is invoked. Deferring the creation of trash-directory until it is actually needed will even improve your startup time.


If, however, you want to use my-trash-dir as a variable for other purposes, there is nothing wrong with using a plain setq to define it:

(setq my-trash-dir (locate-user-emacs-file ".trash"))
(setq trash-directory my-trash-dir)
(unless (file-exists-p my-trash-dir)
  (make-directory my-trash-dir))

There is almost never a need for users to use defconst, especially given the Emacs philosophy centred around customisability. But there are several advantages to using a defvar:

(defvar my-trash-dir (locate-user-emacs-file ".trash")
  "Personal Emacs trash directory.")

(setq trash-directory my-trash-dir)
(unless (file-exists-p my-trash-dir)
  (make-directory my-trash-dir))
  1. You can associate a docstring with it which will be presented by C-hvmy-trash-dirRET and reduces the need for comments in your code.

  2. Emacs notes the file in which the variable was defined. You can then jump to this location via M-xfind-variableRET or the hyperlinked button in the *Help* buffer.

  3. The byte-compiler is made aware of the variable so that it does not complain, should you want to byte-compile your code. The variable also satisfies special-variable-p, should you ever care about this.

  4. You will be one step closer to achieving Emacs zen[1]. In other words, it is more idiomatic and elegant to define variables prior to their use.

    [1]: This claim is provided "as-is", without warranty of any kind.

Basil
  • 12,019
  • 43
  • 69
4

I think Basil gave you the best answer, but just for completeness, you can also use let in your example:

(let ((my-trash-dir
       (expand-file-name ".trash" user-emacs-directory))
  (if (not (file-exists-p my-trash-dir))
      (make-directory my-trash-dir))
  (setq trash-directory my-trash-dir))
Stefan
  • 26,154
  • 3
  • 46
  • 84
2

That will work just fine, but you can simplify it:

(setq trash-dir (expand-file-name ".trash" user-emacs-directory))
(if (not (file-exists-p trash-dir))
    (make-directory trash-dir))
db48x
  • 15,741
  • 1
  • 19
  • 23