Subject: Re: bug#76023: 31.0.50; Observed behavior for substitute-in-file-name different from the doc string

From: Eli Zaretskii <[email-masked]>
Date: Tue, 04 Feb 2025 16:11:45 +0200

> From: arthur miller <[email-masked]>
> CC: "[email-masked]" <[email-masked]>
> Date: Tue, 4 Feb 2025 06:25:21 +0000
> 
> > primitives that accept file names support both flavors of slashes.
> > Example:
> >
> >   (file-name-nondirectory "d:\\foo/bar\\baz")
> >    => "baz"
> 
> I know, I have implemented most of them in CL by now, and discovered they 
> work so. They also all emit out Emacs canonical namestrings; it is only those
> two that don't (if I haven't missed some). It is easy and cheap to make them to
> emit path in the same form as the rest. I first thought not to hack them, but I
> did since I was anyway looking at the code. In the case of substitute-in-file-name,
> it is just to call dostounix_filename on the result:

First, dostounix_filename can only be called safely after the file
name was converted to UTF-8, so it is not safe with unibyte
(undecoded) file names, something that happens during a short period
of startup.  So inserting it requires some auditing.

More importantly, I would hesitate making such changes in such old and
stable functions.

> And in file-name-concat is just to check the last written char for an argument:

file-name-concat is specifically intended to work unlike
expand-file-name, and just concatenate the parts and nothing else.  So
it only caters to backslashes vs forward slashes where it needs to
determine whether or not to add a slash, but otherwise it leaves it to
the caller to format the file-name parts as they see fit.  So I think
it would be a mistake to add such transformations to that function.

> > So the only case where a Lisp program will fail for such file names is
> > if that Lisp program manually analyzes the file name, instead of using
> > Emacs primitives.  In which case I'd say the Lisp program has a bug.
> 
> Depends on. People are creative when writing programs and puting Emacs to
> different use these days. But it is not so much about what is wrong or correct
> usage, it is more about the principle of least surprise and having uniform
> behavior for the api.

IME, people get surprised about quite a few aspects of file names,
their handling on different systems, and in particular on MS-Windows.
So my warm advice to everyone is not to invent their own code that
handles file names, but rely on Emacs primitives instead.

> > But we digress, I think?
> 
> You can close the bug, I understand why do you say it is not a bug. Thank you
> for the patience and helping me to understand it.

Closing.

> Also if you add a short sentence that says "if an expansion results in an
> absolute path, part of the file name before the expansion is discarded" it wont
> hurt. Or somthing in that line. It is a little bit arcane function that does
> some more than described in the doc string.

That's the part which talks about "//", it just is worded in a way
that has only Posix filesystems in mind.  I guess it won't do any harm
to make that more general; done.

> > And why is that a problem?  (Of course, one should almost never use
> > file-name-concat, it exists for a small number of very special cases;
> > everything else should use expand-file-name.)
> 
> How should I know it is meant to be for a special cases?

You are not supposed to know about that function at all ;-)

> There is nothing about
> special cases in docs. :) You have to document stuff. I write everywhere that
> Emacs is *the* best documented Lisp in existence. 

Emacs has the best documentation where documentation is contributed.

> To note, expand-file-name always returns absolute file name. If someone
> would like to construct a relative path programmatically than perhaps that
> function is more apropriate?

They should use expand-file-name followed by file-relative-name.

> I don't know if that is a realistic use-case
> but I can imagine it would be useful in that scenario.

It is indeed a real-life scenario, and it is covered in the manual.