3

I cannot understand the behavior of this simple code:

(defun foo (str bool)
  (interactive
    (list (read-string "Some text: ")
          (y-or-n-p "Yes or no? ")))
  (message "%s is first" str)
  (if bool (message "%s is in if" str)))

When I call it with M-x foo, it prompts for a string input -- which I give as this -- then Yes or no? Good so far. But if I type in n, it prints out this is first. But if I choose y, it seems to jump past the (message "%s is first" str) line and enter the if, which is true (not nil), printing this is in f. Why is the line before if... being skipped if I choose y?

Drew
  • 75,699
  • 9
  • 109
  • 225
147pm
  • 2,907
  • 1
  • 18
  • 39

2 Answers2

7

Forms in the function body are executed in order, just as you would expect.

When you choose "y" if does not "jump" past the first message call. If looks like it did because the first message gets immediately replaced by the second one.

To check that this is true, open the *Messages* buffer and then do M-x foo. You will see that foo adds two messages to the bottom of this buffer, as expected.

You can also use edebug and step through your function to see what happens. To instrument a function for edebug, put the cursor somewhere inside the defun form and press C-u C-M-x.

Constantine
  • 9,072
  • 1
  • 34
  • 49
  • What about the y/n? I learned that anything besides `nil` is considered true. So why does the `if` statement fail with `n`? Is `n` the same as `nil`? – 147pm Dec 12 '15 at 16:58
  • No, `n` is not the same as `nil`. The `if` condition is false when you answer "n" because the function [`y-or-n-p`](https://www.gnu.org/software/emacs/manual/html_node/elisp/Yes_002dor_002dNo-Queries.html#Yes_002dor_002dNo-Queries) returns `t` if the user types `y`, `nil` if the user types `n`. (See the link to the manual.) – Constantine Dec 12 '15 at 17:07
3

It's not being skipped. The second message is printed after the first message is printed, but there is no wait between the two, so you do not notice the first message. Look in buffer *Messages* and you will see both messages.

To give the user time to see the first message, you can use sit-for or sleep-for after it:

(defun foo (str bool)
  (interactive (list (read-string "Some text: ")
               (y-or-n-p "Yes or no? ")))
  (message "%s is first" str)
  (sit-for 2)
  (when bool (message "%s is in if" str)))
Drew
  • 75,699
  • 9
  • 109
  • 225