0

Why does this function print non-zero integers on non-empty lines?

;; taken from https://emacs.stackexchange.com/a/16826/10896
(defun current-line-empty-p ()
  (interactive)
  (setq answer (string-match-p "^\\s-*$" (thing-at-point 'line)))
  (message "%s" answer)
  answer)

I would like the answer to be displayed as t or nil. But on a non-empty line, it prints 35 or some other non-zero integer depending on which line I called it via M-x. On blank lines it prints 0.

Sure non-zero means false and zero means true but I am curious why this behaviour happens? I would have thought string-match-p already returned booleans.

6
  • 3
    You need to read the doc for string-match which is like string-match-p but does not change the match data. string-match returns the index of the first match of the regexp or nil if the regexp did not match at all.
    – Tobias
    Nov 23, 2018 at 1:39
  • 2
    I've seen several questions from you recently which suggest that you're not making use of the in-built documentation (especially C-h f <function>). Saying "I would have thought string-match-p already returned booleans." is silly when the function tells you that it works like string-match and that docstring explicitly tells you it returns the "index of start of first match" which is obviously not the same thing as returning t. The documentation is really good. Ask questions here if it's still unclear, but make sure you're actually checking the documentation first and foremost.
    – phils
    Nov 23, 2018 at 5:34
  • 1
    Something to be very aware of is that in elisp nil is boolean false, and anything else is boolean true. Therefore predicate functions frequently return something other than t for true results, because that other value is potentially more useful, while still being 'true' in a boolean test.
    – phils
    Nov 23, 2018 at 5:38
  • And on that note, "Sure non-zero means false and zero means true" is incorrect. nil means false, and both zero and non-zero means true (provided, of course, that the non-zero is also non-nil).
    – phils
    Nov 23, 2018 at 5:43
  • This is also why you will very frequently see the term "non-nil" used in the documentation, as that is the most unambiguous way of saying "boolean true".
    – phils
    Nov 23, 2018 at 5:58

1 Answer 1

3

What happens is that thing-at-point will return a line such as "hello\n" so your regexp will successfully match with ^ matching right after the \n (which is indeed a "beginning of line) followed by zero repetitions of \s- followed by a match for $ at end of line.

string-match-p doesn't just return t upon success but it returns the position of the beginning of the match (e.g. 6 in my example).

The way I'd write your code would be:

(defun current-line-empty-p ()
  (interactive)
  (save-excursion
    (forward-line 0)  ;; Go to beginning of current line.
    (let ((answer (looking-at "[ \t]*$")))
      (message "%S" answer))))

Note that I avoided the allocation of a temporary string and I avoided the \s- regexp which rarely does quite what you need.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.