22

What problem can happen if the goto-line function is used in a non-interactive elisp program? Its docstring gives a warning saying that:

This function is usually the wrong thing to use in a Lisp program. What you probably want instead is something like:

(goto-char (point-min)) (forward-line (1- N))

Moreover, when I try to byte-compile-file my init file including goto-line, I get a unpleasant warning like this once again:

.emacs:170:19:Warning: `goto-line' used from Lisp code
That command is designed for interactive use only

Is using goto-line in a non-interactive program really so dangerous? Relatedly, why is the suggested forward-line solution preferable?

dkim
  • 3,930
  • 1
  • 33
  • 37
  • Not sure how goto-line would work not interactively, it goes to a line in the current buffer – Jon Lin Aug 04 '12 at 03:07
  • @JonLin You can find an example that non-interactively uses `goto-line` at [EmacsWiki:AUCTeX](http://emacswiki.org/emacs/AUCTeX#toc20):`th-evince-sync`. – dkim Aug 04 '12 at 03:35
  • event_jr has answered your question as posed, but still *why* are you trying to do this? There may be a better way to accomplish what you really want. Also, I would point out that if the buffer has been narrowed going to a certain line probably isn't going to do what you think it is. – scottfrazer Aug 04 '12 at 10:40
  • @scottfrazer At first sight, because of its name, the `goto-line` statement appeared to be a more intuitive (and compact) way to go to the _n_-th line than the `forward-line` idiom. Moreover, I came across some programs on the Internet that were using `goto-line` non-interactively. Now I understand that `goto-line` can have some side-effects that a developer might not expect. As for narrowing, `forward-line` is also resctricted to the accessible portion of a buffer. – dkim Aug 04 '12 at 13:58

2 Answers2

30

Firstly, this prevents Elisp programmers from fall into bad habits -- writing inefficient code in a line-number centric way. i.e. instead of using (forward-line 1) calculating the current line number, incrementing, and using goto-line.

From this mailing list article:

In a nutshell, the reason why goto-line should not be a frequently used command is that normally there's no reason to want to get to line number N unless you have a program that told you there's something interesting on that line.

Secondly, goto-line manipulates the user's environment in addition to moving the point (i.e. push-mark). For non-interactive use, this may not be what you want. On the other hand if having considered all this, you believe goto-line is exactly what you need, then just call it like this:

(defun foo ()
  (interactive)
  (with-no-warnings
    (goto-line N)))

And you won't get any compiler warnings.

Stefan
  • 27,908
  • 4
  • 53
  • 82
event_jr
  • 17,467
  • 4
  • 47
  • 62
  • 1
    "normally there's no reason to want to get to line number N unless you have a program that told you there's something interesting on that line" — what if your program (or elisp code) has computed that there _is_ indeed something interesting on that line? Then is the recommendation to subtract current line from that line, and use forward-line instead? (Easy, but just making sure.) – ShreevatsaR Sep 18 '16 at 09:32
  • I prefer to use `funcall-interactively` to suppress that particular compiler warning, as it would not swallow other potential warnings. I.e. `(funcall-interactively #'goto-line N)` – Aaron Jul 28 '22 at 14:26
6

in addition to what was said:

"goto-line" finally recurs onto "(forward-line (1- line)", which in effect does the work. All other of the 43 lines of "goto-line" command body deal with interactive use. For example considering a possibly universal argument.

When writing a program resp. when running it, your computer is in another state than following an interactive call. Thus you should address this state by using "forward-line" straight on.

Andreas Röhler
  • 4,804
  • 14
  • 18
  • 1
    The `(interactive arg-descriptor)` part that deals with interactive use looks like being skipped when `goto-line` is called from Lisp programs. From [the reference manual](http://www.gnu.org/software/emacs/manual/html_node/elisp/Using-Interactive.html#index-interactive-1253), "A command may be called from Lisp programs like any other function, but then the caller supplies the arguments and _arg-descriptor_ has no effect." – dkim Aug 05 '12 at 20:00
  • @dkim Also code beyond calculation of the argument deals with interactive use: there is still push-mark, switch-to-buffer and the like. – Andreas Röhler Jun 08 '15 at 11:30