Subject: RE: [External] : Re: bug#56673: 26.3; Doc of `file-equal-p'

From: Drew Adams <[email-masked]>
Date: Thu, 21 Jul 2022 16:12:29 +0000

> > 1. I don't understand this part of the doc (in both doc string and
> > manual):
> >
> >   If FILE1 or FILE2 does not exist, the return value is unspecified.
> >
> > What's that about?
> 
> It means the result could be anything: nil or non-nil, and you
> shouldn't expect anything specific.  IOW, don't call this
> function unless both files exist.
>
> > In what case(s) is the result unspecified because 
> > one or both file doesn't exist?
> 
> All of them.  There was a long discussion of this in 
> bug#10489, and I'm not interested in reopening it.

Thanks for reminding me of that thread. I've scanned
it again now.

My review of the thread reinforces to me that the
_only_ case where a nonexistent file could possibly
result in a non-nil return value is when a file
handler is used.

Do you disagree that that's the only case?

If that's the only case, then could we perhaps say
something like this (statement, not wording)?

 If neither file name has a `file-equal-p' handler
 then if either file does not exist the return
 value is nil.

 If either name has a `file-equal-p' handler then
 the return value could be nil or non-nil when
 either file does not exist.

That first paragraph lets users know about an
important, common use case - they may well know
that no handler is involved in their use context.

IIUC (correct me if wrong, please), code such as
this would be correct, to handle the handler case
also.  But it would be costly, and would make
useless any optimization a handler might make by
not testing for existence.

(defun file-equal-existing-p (file1 file2)
 "..."
 (let ((handler (or (find-file-name-handler file1 'file-equal-p)
                    (find-file-name-handler file2 'file-equal-p))))
    (if handler
        ;; Or a different `and' order...
        (and (funcall handler 'file-equal-p file1 file2)
             (file-exists-p file1)
             (file-exists-p file2))
      (let (f1-attr f2-attr)
        (and (setq f1-attr (file-attributes (file-truename file1))
                   f2-attr (file-attributes (file-truename file2)))
             (equal f1-attr f2-attr))))))

And code such as this would cover the simple use case:

(defun file-equal-no-handler-p (file1 file2)
 "..."
 (let ((handler (or (find-file-name-handler file1 'file-equal-p)
                    (find-file-name-handler file2 'file-equal-p)))
       f1-attr f2-attr)
    (and (not handler) 
         (setq f1-attr (file-attributes (file-truename file1))
               f2-attr (file-attributes (file-truename file2)))
         (equal f1-attr f2-attr))))))

> > 2. How about adding this sentence from the manual to 
> > the doc string (also)?
> >
> >   This is similar to comparing their truenames, except that
> >   remote file names are also handled in an appropriate manner.
> 
> The doc string already says that, albeit with different words.

I don't see how it even vaguely suggests that,
in any way.  Could you point to the wording you
think "already says that"?

We have lots of `file-*' functions.  It's fairly
important that we make clear what each does, so
users can make best use of them.