(make-pathname :directory '(:relative "bar") :name "foo"
:defaults *default-pathname-defaults*) [1]
and
(merge-pathnames
(make-pathname :directory '(:relative "bar") :name "foo")
*default-pathname-defaults*) [2]
intended to give the same answer? ("Same", for the purpose of this
question, meaning "prints identically") The implementation I'm
looking at has different rules for merging in each case, thus:
* *default-pathname-defaults*
#P"/home/dan/src/sourceforge/sbcl/"
* (make-pathname :directory '(:relative "bar") :name "foo" :defaults *default-pathname-defaults*)
#P"bar/foo"
* (merge-pathnames (make-pathname :directory '(:relative "bar") :name "foo") *default-pathname-defaults*)
#P"/home/dan/src/sourceforge/sbcl/bar/foo"
The description of make-pathname says that "after the components
supplied explicitly by host, device, directory, name, type, and
version are filled in, the merging rules used by merge-pathnames are
used to fill in any unsupplied components", so I could almost believe
I'm getting a correct answer for case [1] - the directory is supplied
explicitly, so no merging is done.
However, the description for merge-pathnames is very similar: it says
"Constructs a pathname from pathname by filling in any unsupplied
components with the corresponding values from default-pathname and
default-version", - i.e. it also is only supposed to merge unsupplied
components. However it then goes on to describe the rules for merging
when the primary argument has a relative directory component, so it's
pretty clear (to me anyway) that relative directories should be merged
even though the directory was a "supplied component" to start with.
I'd _like_ the same behaviour from make-pathname - can I reasonably
expect it, or does "unsupplied components" _really_ mean
not-even-partly-supplied in that case?
-dan
--
http://ww.telent.net/cliki/ - Link farm for free CL-on-Unix resources
> Assuming that *default-pathname-defaults* contains a directory
> component, are
>
> (make-pathname :directory '(:relative "bar") :name "foo"
> :defaults *default-pathname-defaults*) [1]
>
> and
>
> (merge-pathnames
> (make-pathname :directory '(:relative "bar") :name "foo")
> *default-pathname-defaults*) [2]
>
> intended to give the same answer?
No.
> ("Same", for the purpose of this
> question, meaning "prints identically") The implementation I'm
> looking at has different rules for merging in each case, thus:
>
> * *default-pathname-defaults*
> #P"/home/dan/src/sourceforge/sbcl/"
> * (make-pathname :directory '(:relative "bar") :name "foo" :defaults *default-pathname-defaults*)
> #P"bar/foo"
Correct.
> * (merge-pathnames (make-pathname :directory '(:relative "bar") :name "foo") *default-pathname-defaults*)
> #P"/home/dan/src/sourceforge/sbcl/bar/foo"
Correct.
> The description of make-pathname says that "after the components
> supplied explicitly by host, device, directory, name, type, and
> version are filled in, the merging rules used by merge-pathnames are
> used to fill in any unsupplied components",
As a rule, I don't like to speak for the community, but this is an area
that it's really important that people agree. I've had extensive discussions
about this phrasing with lots of people from multiple vendors, and the
consensus is that most of us want this to mean "unsupplied" in this
context to mean "not supplied as an explicit argument to make-pathname".
This is essential since otherwise there would be no way to make a
pathname that did not get defaulted; further, make-pathname is the right
operator to do that. It is unfortunate phrasing in the spec. The pathname
chapter is one of the ones I feel I did the least well on--it was high
on my list to spend more time on, had I had more time to spend before we
had to go to press. Sorry.
> so I could almost believe
> I'm getting a correct answer for case [1] - the directory is supplied
> explicitly, so no merging is done.
Yes.
> However, the description for merge-pathnames is very similar: it says
> "Constructs a pathname from pathname by filling in any unsupplied
> components with the corresponding values from default-pathname and
> default-version", - i.e. it also is only supposed to merge unsupplied
> components. However it then goes on to describe the rules for merging
> when the primary argument has a relative directory component, so it's
> pretty clear (to me anyway) that relative directories should be merged
> even though the directory was a "supplied component" to start with.
That's right. This function is intended to go farther than make-pathname.
> I'd _like_ the same behaviour from make-pathname - can I reasonably
> expect it, or does "unsupplied components" _really_ mean
> not-even-partly-supplied in that case?
Sorry. I think if you got the same pathname from MAKE-PATHNAME it would
break a billion extant programs.
You should just write
(defun make-defaulted-pathname (&rest keys)
(merge-pathnames (apply #'make-pathname keys)
*default-pathname-defaults*))
or some such thing and use that.
> As a rule, I don't like to speak for the community, but this is an area
> that it's really important that people agree. I've had extensive discussions
> about this phrasing with lots of people from multiple vendors, and the
> consensus is that most of us want this to mean "unsupplied" in this
> context to mean "not supplied as an explicit argument to make-pathname".
That's cool.
> This is essential since otherwise there would be no way to make a
> pathname that did not get defaulted
Just to be picky, though, I don't see how that's a reason. The value
of defaults if unsupplied is not *default-pathname-defaults*, it's "a
pathname whose host component is the same as the host component of the
value of *default-pathname-defaults*, and whose other components are
all nil." So, you get a host merged in, but the other components left
intact. A relative directory component merged against NIL should
stay relative, no?
Still, if people are supplying a relative :directory and a :defaults
that has a directory component, and expecting them not to get merged,
then yes, I agree that that's what should happen. I was just surprised.
Wrapping calls in (merge-pathname ...) is no big deal.
> Just to be picky, though, I don't see how that's a reason. The value
> of defaults if unsupplied is not *default-pathname-defaults*, it's "a
> pathname whose host component is the same as the host component of the
> value of *default-pathname-defaults*, and whose other components are
> all nil." So, you get a host merged in, but the other components left
> intact.
You get the host merged in because the Lisp Machine did it that way.
It never had hostless pathnames and they were afraid of what it owuld mean.
For Macsyma, I implemented a pathname-like object that did the right thing
here, by having my own object with a pathname inside it to respond to
services I was too lazy to implement, and an extra slot to keep track of
whether to believe the host in the pathname since I knew the host was
sometimes real and sometimes an artifact. I know what the effect of that
merging is, and I can tell you with all personal certainty that this is
a HUGE error in the design of the common lisp pathname system--one you
can hardly see, though , on implementations with only access to a single
files system--but, ironically, very visible on the Lisp Machine, where you
routinely deal with multiple networked file systems.
I would not compound this bug by having it apply to other cells. MAKE-PATHNAME
ought to give you a pathname with just those slots filled that you asked for,
or the closest to that that the spec would allow.
> A relative directory component merged against NIL should
> stay relative, no?
You mean if *default-pathname-defaults* has NIL there. Yeah, I assume so.
Though it would confuse the Lisp Machine. The reason there is that pathnames
are interned, so #P"foo/bar" is an interned pathname. In Lisps you're
familiar with, there is always a single, unique working dir associated
with the Lisp process, so this doesn't bother you. But the LispM is working
over the net, so diferent processes might access the file system remotely
through different user shells. That means you've got multiple processes,
maybe or maybe not owned by different users, but each with a potentially
different user dir, and each such dir potentially opaque to the local
machine. When the LispM wants to check for file collisions, to not write
over files, etc., it tries to do EQ or NEQ checks, which don't work well if
relative pathnames are expected to be the last word the process has.
It really wants everything to bottom out to absolute filenames. And I can't
say as I blame it. It gets in enough trouble when there are file systems
where two different strings resolve to the same filename. e.g., Tops-20
PS:[FRED]FOO.LISP vs DSK:[FRED]FOO.LISP might be the same file.
To really understand how these things work, you need to work backwards from
the question of what services the system and the file system might be trying
to do for you, and then think of your personal social contract to obey enough
hygiene that you don't interfere with the ability of them to do that. A lot
of people want relative pathnames in *default-pathname-defaults* to work, but
it's an iffy goal. Because it ties the hands of those trying to help you.
The Lisp Machine's EQ-ified pathnames is not something reuqired by the spec,
either. But it is permitted. And it's a huge speed savings on some
operations to be able to compare pathnames by EQ. Still, it surprises some
users. Some implementations let you setf pathname components, for example.
But the Lisp Machine can't--that would cause a disaster with constants shared.
> Still, if people are supplying a relative :directory and a :defaults
> that has a directory component, and expecting them not to get merged,
> then yes, I agree that that's what should happen. I was just surprised.
> Wrapping calls in (merge-pathname ...) is no big deal.
Well, I certainly agree it *is* a hassle. But hassles that serve a
known purpose are easier to endure.