openlang

My init set fill-column for exactly one buffer

Had (setq fill-column 72) in my init for ages and only just noticed that M-q in a fresh buffer still wraps at 70. (In *scratch* it wraps at 72, which is how I fooled myself.)

fill-column is automatically buffer-local. Setting one of those with setq doesn't touch the default. It makes a local value in whatever buffer is current when the line runs. During init that's usually *scratch*, so *scratch* got 72 and every other buffer started from the untouched default.

(setq fill-column 72)          ; local to the current buffer only
(setq-default fill-column 72)  ; the value new buffers start with

C-h v fill-column says so right in the help text, "Automatically becomes buffer-local when set". I'd read that sentence a dozen times and never connected it to my own init. Now going through the rest of the file looking for the same mistake.

The conversation continues 8

Follow the reasoning
  1. Permalink

    Count them before fixing anything. This gives the number of buffers holding their own value.

    (seq-count (lambda (b) (local-variable-p 'fill-column b))
               (buffer-list))

    If the answer is 1, it's the init line. If it's more, something else is setting it locally too, and setq-default won't change those buffers either.

  2. Permalink

    The way I keep it straight is two questions in order. First, which value does a new buffer read? The default, so that's the one the init file has to set. Then, which buffers already have a local value? Those keep it, whatever the default says afterwards. It's close to a Python class attribute and an instance attribute, with setq-default setting the class attribute and setq on an automatically buffer-local variable assigning on the instance.

  3. Permalink

    The analogy holds for fill-column and breaks one variable over. Take an ordinary variable, one nobody marked with make-variable-buffer-local. With no local value in the current buffer, setq sets the global value and every buffer sees it. In Python an assignment through an instance always lands on the instance. So whether setq behaves like self.x = 1 or like Cls.x = 1 depends on a declaration somewhere else in the source, which is exactly the sort of quiet cleverness I'd like the help buffer to keep shouting about.

  4. Permalink

    One point on the scope of the fix. setq-default sets the default value and leaves existing local values alone. It corrects buffers created after the init line runs, while a buffer that already has a local fill-column, here *scratch*, keeps whatever the earlier setq or a mode gave it. For a clean result in the running session, that stale local value has to be removed with kill-local-variable in the buffer concerned.

  5. Permalink

    Same thing got me in a commit message buffer. M-q wrapped at 70 there and at 72 in *scratch*, and I spent a while blaming the commit mode, which never had a local value at all.

  6. Permalink

    Ran it. 3, not 1. *scratch* from the init line, plus two buffers where a mode hook of mine was doing a plain setq on it. C-h v in one of those shows the split too, the local value for that buffer and the global value next to it, which is quicker than the count once you already suspect a particular buffer. The hooks now use setq-local, so the intent is written down where it happens.

  7. Permalink

    Fair, and the help buffer does shout, just only after you go and look. Inside code my answer is setq-local (it makes the variable local first and then sets it, whatever the declaration says), so a reader doesn't need to know the declaration at all. In the init file I've moved the per-buffer ones to setq-default, kept plain setq for the rest, and put a short comment next to the odd ones.

  8. Permalink

    That bit me while testing, in the other direction. I tried (setq-default fill-column 80) from *scratch* to watch the effect, and *scratch* itself stayed at 72 because of the local value the init had given it. M-x kill-local-variable there, and it went to 80 straight away. (Restarting would have done it as well, but I had too many buffers open to want that.)

Other sides of the same question

  1. A hung test reads better from its dump than from prints

    When a test used to hang, I'd sprinkle fmt.Println around and run it again. These days I do something else. I set a short tim…

    Replies 9go
  2. SilentlyContinue is On Error Resume Next with better spelling

    Went from inherited workbooks to inherited PowerShell scripts and found my old friend in a new coat. -ErrorAction SilentlyCon…

  3. Upgradeable means the storage layout is forever

    People hear proxy pattern and think the immutability problem went away. It moved. The proxy holds the state and forwards call…