3

The haskell-mode-hook customizable variable in haskell-mode has a default value of (haskell-indentation-mode interactive-haskell-mode).

Yet, after starting Emacs, its value is nil; the "original value" is given as (haskell-indentation-mode interactive-haskell-mode). This suggests that something else set its value to nil, but I can't figure out what.

Grepping through ~/.emacs.d/elpa doesn't turn up anything that sets haskell-mode-hook to nil, and nothing in my init file does either.

Is anyone else having this issue?

Drew
  • 75,699
  • 9
  • 109
  • 225
Tianxiang Xiong
  • 3,848
  • 16
  • 27
  • 2
    Looks like a bug, I ran into a similar problem before. The proper solution for this would be defining the customizable with `nil` as initial value, then have the mode add both functions to the hook. That way the user can add hooks before the mode is loaded and the mode's hooks are added as well. – wasamasa Nov 28 '16 at 08:52
  • Do you suppose this is a bug with `defcustom` or something else? Are you using Emacs 25.1? – Tianxiang Xiong Nov 29 '16 at 07:30
  • 1
    It's a bug in haskell-mode to do this as it can be overridden too easily. – wasamasa Nov 29 '16 at 07:58
  • Alright, but I can't find where it's being overridden, which is strange. – Tianxiang Xiong Nov 30 '16 at 06:54
  • 1
    Bug filed. https://github.com/haskell/haskell-mode/issues/1480#issuecomment-276557743 – jrm Feb 01 '17 at 02:43
  • @TianxiangXiong: It gets 'overridden' in haskell-mode.el itself (or more precisely, the would-be default value is never set in the first place). It's not a problem with your config; it's a bug in the library. – phils Oct 16 '17 at 06:41
  • @Drew OK, done. – wasamasa Sep 24 '18 at 21:22

1 Answers1

2

Here's what happens, for those of you who write and hack on packages:

Emacs tries balancing the customization abilities and expressiveness of its extension language. This is why defvar (and by extension, defcustom) behaves in a somewhat surprising way. Consider this:

(defvar foo 42) ; define foo with 42 as value
(setq foo 13) ; set foo to 13

Nothing special here. A variable is declared and initialized, then it's set to a different value. What happens if we do it the other way around?

(setq foo 13) ; set foo to 13, defining it in the process
(defvar foo 42) ; marks variable as special, but doesn't change value

You might have expected that the defvar overrides the previous assignment, but Emacs treats this case deliberately different. The idea is that if the user has set a variable before it has been declared and initialized, whatever the user set it to shall stay its value. Therefore the defvar merely marks the variable as special, but doesn't change its value. This is usually the right thing to do with customizables.

Now, imagine we're not working with foo, but a hook variable and the contents aren't a number, but a list of symbols. In this case we really want to start out with a meaningful value (as opposed to it being ignored if the variable is set before that) and allow the user (or any code of our own) to add functions. For this case there's the following idiom:

(defvar some-hook nil)
(add-hook 'some-hook 'foo)
(add-hook 'some-hook 'bar)

Suppose the user did (add-hook 'some-hook 'baz). No matter whether this has been evaluated before or after the above code, you'd always have the functions foo and bar and baz in the hook, only the ordering would be different. This is the recommended pattern for hooks and other customizables where the initial contents matter.

wasamasa
  • 21,803
  • 1
  • 65
  • 97
  • See also [Is there an equivalent for defparameter on emacs-lisp?](https://emacs.stackexchange.com/questions/35294/is-there-an-equivalent-for-defparameter-on-emacs-lisp) – npostavs Sep 24 '18 at 23:49