Hacker News new | ask | show | jobs
by hollerith 4259 days ago
Your code fails to suppress beeping behavior on my Mac for certain values of beeping-function. In particular, when I eval the following, I get a beep.

  (require 'cl)

  (setq lexical-binding nil)

  (defun beeping-function ()
      (save-excursion
          (set-buffer "*Messages*")
          (goto-char (point-max))
          (scroll-up)))

  (letf (((symbol-function 'beep) (lambda ())))
      (beeping-function))
I tried to repair it: I ran the code in a fresh Emacs session to which my usual customizations in .emacs had not been applied. I set lexical-binding to t. Since beep is an alias for ding, I replaced beep with ding. I rewrote the letf as a cl-flet.

I think that the fact that scroll-up is built-in is pertinent: there was another incident in the recent past in which the function whose binding I wanted to override ("shadow"?) is called from a built-in function and in which my attempt to use cl-flet to override the binding failed.

If you have Emacs running on a Windows or Linux machine, I would like to know whether the above code causes a beep on that machine. I would like to know because in the past, code that gets a little tricky about bindings that worked on my friend's Windows box failed to work on my Mac (even with an up-to-date Emacs).

ADDED: Actually, let me show you the code that "worked" (i.e., behaved like someone familiar with Scheme or Haskell would expect modulo the trivial "rigamarole" of needing to use funcall) on my friend's Windows box but not on my Mac. The error is "(void-variable a)".

  (funcall
      (funcall
          (lambda (a) (lambda (b) a))
          1)
      2)
1 comments

As you can easily check with M-x find-function a `scroll-up` function is implemented in C. This is a known problem - I can't find it right now, but I remember I once read a blog post where the author complained about this: in general you're not going to get good results when trying to advise, override or modify C-level functions from Elisp code.

IIRC cl-flet was recently (well, in the current decade I think :)) modified to be lexically scoped, so that won't work (anymore). This is why I had to use `letf` with `(symbol-function 'symbol)` instead of a neater `(flet ((beep ())) ...)`.

Personally I deal with beeping like this:

    (setq ring-bell-function (lambda ()))
but this disables any beeping, which may not be what you want. In short, things you `setq` or more generally `setf` tend to be visible from C functions (no guarantees though).

On the other hand my Emacs (on Linux) refuses to beep in any circumstances even if I run it with `emacs -Q` and do M-: (beep) - I have no idea why, I suspect it's either my sound configuration or has to do with the way I built my emacs from source.

I'd say for this:

    (funcall
      (funcall
          (lambda (a) (lambda (b) a))
          1)
      2)
raising a (void-variable a) error is correct behaviour under dynamic scoping. On my system (Emacs 25.0.50.2 x86_64-unknown-linux-gnu) it fails with void-variable under normal circumstances, but returns 1 when used with lexical scoping enabled. If your Emacs behaves differently (and remember to always check with emacs -Q just to be sure it's not something in your config) that's probably a bug.
>If your Emacs behaves differently . . . that's probably a bug.

Yes, it behaves differently (with lexical-binding set to t and with the -Q flag).