Subject: bug#21391: 24.5; `thing-at-point' should return a string

From: Dmitry Gutov <[email-masked]>
Date: Thu, 10 Nov 2016 01:30:20 +0200

On 09.11.2016 17:45, Eli Zaretskii wrote:

> I don't think I understand what you are suggesting.  Can you show a
> proposed patch, so I could see the light?

See the attached patch.

Or to take a step further, we might want to deprecate the 
`thing-at-point' property, and recommend to only use the 
`bounds-of-thing-at-point' property. This way, we get the string-ness 
guarantee automatically, and the bounds-of-thing-at-point function will 
work for all things (it currently fails for `number').

>>> If
>>> there is such code, why would we want to break it?  To what end?  And
>>> if no code uses this loophole, why do we care that it exists?
>>
>> To make thing-at-point behavior more consistent.
>
> It is consistent now.

Put point on a number. Number is a sexp. Not all sexps are strings.

(thing-at-point 'number) => 123
(thing-at-point 'sexp) => "123"

That doesn't looks consistent to me. And there's no way to guess the 
return value type in advance without knowing which exact function is the 
thing's `thing-at-point' property.

> The only way to make it inconsistent is to have
> a 'thing-at-point' property that violates that, but we never do that
> in Emacs proper, so if someone else does that, it would be their bug.

number's `thing-at-point' property is not like the others.
diff --git a/lisp/thingatpt.el b/lisp/thingatpt.el
index 9920fa0..1c630f7 100644
--- a/lisp/thingatpt.el
+++ b/lisp/thingatpt.el
@@ -128,7 +128,7 @@ bounds-of-thing-at-point
 
 ;;;###autoload
 (defun thing-at-point (thing &optional no-properties)
-  "Return the THING at point.
+  "Return the THING at point as a string.
 THING should be a symbol specifying a type of syntactic entity.
 Possibilities include `symbol', `list', `sexp', `defun',
 `filename', `url', `email', `word', `sentence', `whitespace',
@@ -145,7 +145,7 @@ thing-at-point
            (let ((bounds (bounds-of-thing-at-point thing)))
              (when bounds
                (buffer-substring (car bounds) (cdr bounds)))))))
-    (when (and text no-properties (sequencep text))
+    (when (and text no-properties)
       (set-text-properties 0 (length text) nil text))
     text))
 
@@ -557,6 +557,14 @@ thing-at-point-email-regexp
 (put 'buffer 'end-op (lambda () (goto-char (point-max))))
 (put 'buffer 'beginning-op (lambda () (goto-char (point-min))))
 
+;;  Number
+
+(put 'number 'thing-at-point
+     (lambda ()
+       (let ((thing (thing-at-point 'sexp)))
+         (when (numberp (thing-at-point--read-from-whole-string thing))
+           thing))))
+
 ;;  Aliases
 
 (defun word-at-point ()
@@ -604,7 +612,6 @@ symbol-at-point
 (defun number-at-point ()
   "Return the number at point, or nil if none is found."
   (form-at-point 'sexp 'numberp))
-(put 'number 'thing-at-point 'number-at-point)
 ;;;###autoload
 (defun list-at-point ()
   "Return the Lisp list at point, or nil if none is found."