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.

Drew
  • 75,699
  • 9
  • 109
  • 225
smilingbuddha
  • 1,131
  • 10
  • 26
  • 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 '18 at 01: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 `). 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 '18 at 05: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 '18 at 05: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 '18 at 05: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 '18 at 05:58
  • You can also simply use `string-blank-p` from subr-x.el, i.e., `(string-blank-p (buffer-substring (line-beginning-position) (line-end-position)))`. – xuchunyang Nov 23 '18 at 07:07

1 Answers1

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.

Stefan
  • 26,154
  • 3
  • 46
  • 84