Subject: bug#44186: Recursive mkdir

From: Leo Prikler <[email-masked]>
Date: Mon, 26 Oct 2020 22:05:43 +0100

Hello, divoplade,

> So, after a bit of bikeshedding on #guile, it turns out that the
> controversy moved to the second commit.
Not quite, the second commit just needlessly complicates a patch, that
should not be that complicated in the first place.
When posting a patch to the mailing list, you should do your best to
ensure, that all of your code works as intended (alas, I am getting
ahead of myself here a bit).  It is easier to prove this for *just*
mkdir-p/mkdir-recursive rather than having to test all your wrappers as
well.  You have been pretty adamant, that you need those wrappers, but
they can easily be written in whichever library actually ends up using
them as well, so you're just creating more work for yourself for little
gain.  That's the point I was trying to make in the IRC.

> Here is the justification for it.
> 
> When a program user wants to save data to a file, if the place where
> to
> save the file does not exist yet, there will be an error: "cannot
> create file or directory". That's puzzling to the user, because, yes,
> the user wants to create that file.  If the error is a little more
> precise, it will be something in the line of "Please create directory
> blah/blah/blah before invoking this program".
> 
> So, the user will wonder why the program was not able to create
> blah/blah/blah itself, create it, and re-run the program. This is
> more
> work for the user, work that could have been easily handled by the
> program.
That would be a nice story in a vacuum, but in practice few systems
work like that.  Python errors in a similar way to Guile, but with a
nicer message.  So does plain Node JS.  On the part of Node with all of
its single package modules, even there the equivalent to your versions
of open-output-file is one package[1] removed from the built-in fs
module.

> Good behaving programs should (recursively) create the directory
> before
> trying to write to a file specified by the user. That include log
> files
> for a daemon, for instance. Emacs org-mode babel tangling uses a
> :mkdirp t for a similar reason. In order to simplify the development
> of
> such programs, and in order to avoid bugs where the developer forgot
> to
> call (mkdir-recursive (dirname output-file)) before (open-output-
> file,
> call-with-output-file or with-output-to-file, while still keeping
> compatibility of the other programs, I propose to add a keyword
> argument to these functions. 
The programming of such procedures would not get simpler by inlining
mkdir-p into open-file.  Instead, programs written that way would be
harder to understand, as the implicit creation of such directories
outside of functions that explicitly exist for this implicit creation
will cause (some) confusion as to whether or not implicit creation of
directories can/will take place and whether that is actually wanted in
this context and erroring is not an acceptable alternative.

The addition of mkdir-p/mkdir-recursive/make-directories alone would
already enable a writer of org-mode tangle to write whichever helper
they need for their (in my opinion rather specific) use case in 2
lines. 

> I also simplified the mkdir-recursive function, to be closer to 
> https://gitlab.com/leoprikler/guile-filesystem/-/blob/master/ice-9/filesystem.scm
> .
I'd prefer it if you didn't credit me for messing up your code. ;)
The reason my version works, is because (ice-9 filesystem) has a
working implementation of file-ancestors, which it uses to create all
ancestors in order.  The part you've copied only creates one such
directory.  With the changes you've made, the directory, that does get
created, is the first one in the tree, which does not exist.  I'm
surprised, that this test passes for you, because it does not pass for
me.

On a somewhat related note, I am getting closer to a 0.1.0 release of
(ice-9 filesystem), which I'll then pitch to the Guix mailing lists. 
Being an outside module, that means you can use it with Guile versions
earlier than 3.0.5, which at least in my eyes sounds like a better
solution to your problem of not being able to implement org-babel in
Guile.

Regards, Leo

[1] https://www.npmjs.com/package/fse