(This is the third and final choke-sized chunk. In order to keep any
replies together, I suggest that people reply to this part unless the
reply is very specific to one of the others.)

File-as-dir is a flawed way of expressing parent-child relations.
Unfortunately, when it comes to relations, expressing two-way
parent-child links and providing a tree view of them is what
file-as-dir does /best/.

Even simple two-way relationships that don't have an obvious
parent-child nature cause additional problems. Say we decided to
create metadata to record which of the men are friends. So if Dean
gets along with his brother Ed we could create

/(something)/friend/aardvark:
/(something)/friend/aardvark:1 (which is the file also known as
'/(whatever)/portrait/Ed')
/(something)/friend/aardvark:2 (which is the file also known as
'/(whatever)/portrait/Dean')

using link-directories. In fact, if we have anonymous last name
segments, we can just create

/(something)/friend/aardvark: , which links anonymously to both the Ed
and Dean photos.

But try to express this using subfiles: which of the two brothers will
we arbitrarily choose to make the subfile of the other?

In general, because the subfile relationship is always parent-child,
to express a symmetric relationship in it we have to make up spurious
extra data, declaring one participant in the relationship to be the
'parent' when no such distinction exists. Ed and Dean are unlikely to
care about this, but try deciding whether Sales worksClosely with
Marketing or Marketing worksClosely with Sales on your firm's
computerised org chart. (Apparently things like LDAPisation projects
have provoked wars over less.) And in the link-directory example using
anonymous links, even the dumbest program that knows nothing about
either /(something)/friends or friendship can tell that
/(something)/friends/aardvark: is symmetric. In the link-directory
example that doesn't use anonymous links, it doesn't know that - and
subfile metadata will actively give it the false parent/child
information. And of course even if we already know that a specific
relationship is symmetric, or if it's not important that we find out,
problems two and four from part two bite hard. For example, reliably
finding all of Ed's friends' photos requires looking for both all his
photo's ;friends children and all its ;friends parents every time. We
have similar problems for relationships that aren't symmetric, but for
which we don't want to have to declare one role to be the parent of
the other. Which party in a is-husband-of/is-wife-of relation should
be indicated as the parent?

Then there are (>2)-way relations. Here's a good example of a
three-way relation, lifted from the
Rumbaugh-Blaha-Premerlani-Eddy-Lorensen OO book. Say that we have
files representing programmers, software projects and programming
languages. Now say that, for example, Bob is using Algol 68 on the
Foomatic and both SNOBOL and PL/1 on Project Omega, while Dean is
coding in PL/1 on the Computron and in PILOT on Project Omega, and
Todd is formally specifying the Foomatic in Z. We would represent this
information using link-directories by creating

/(thingy)/impl-lang/aardvark:coder --> /(whatever)/portrait/Bob
/(thingy)/impl-lang/aardvark:lang   --> /bin/algol68
/(thingy)/impl-lang/aardvark:proj    --> /(whatever)/projects/foomatic
/(thingy)/impl-lang/zebra:coder --> /(whatever)/portrait/Dean
/(thingy)/impl-lang/zebra:lang   --> /bin/pilot
/(thingy)/impl-lang/zebra:proj    --> /(whatever)/projects/foomatic

and so on: one link-directory for each triple of programmer, project
and language. If we want to express the same information using subfile
metadata we are going to have to create something like

/(whatever)/portrait/Bob;impl-lang/1/proj   --> /bin/algol68
/(whatever)/portrait/Bob;impl-lang/1/lang   --> /(whatever)/projects/foomatic
/(whatever)/portrait/Dean;impl-lang/1/proj  --> /bin/pilot
/(whatever)/portrait/Dean;impl-lang/1/lang  --> /(whatever)/projects/foomatic

and so on. Problem two is worse in this case. Not only do we have to
look through the path"name"s of /(whatever)/projects/foomatic in order
to find out what programmers are working on it, but in order to find
out what languages Bob is using on the Foomatic we have to find the
/(whatever)/portrait/Bob;impl-lang/* directories among the path"name"s
of /(whatever)/projects/foomatic and then examine those directories'
./language names. And to find out what projects Bob is working on, we
have to list all the /(whatever)/projects/* files which are linked
from /(whatever)/portrait/Bob;impl-lang/*/project . All this is
basically the same as working with link-directories using
base-filesystem commands; indeed /(whatever)/portrait/Bob;impl-lang/1
is basically /(thingy)/impl-lang/aardvark: shoved under an arbitrary
choice of one of the three files it relates.

We created tools so that we could handle parent-child relations
expressed as link-directories without clunkiness; naturally we can do
similar things for relations of other kinds. One generally useful tool
would be something like rels below:

$ cd /(whatever)/portrait/Dean
$ rels
/(something)/father-son (:son) :father
/(thingy)/impl-lang (:coder) :lang :proj
/(thingy)/impl-lang (:coder) :lang :proj
/(something)/friend
$

rels lists the link-directories of which /(whatever)/portrait/Dean is
a descendant. The animal names at the end of each link-directory's
"name" have been omitted, because they don't convey any information
beyond distinguishing between different link-directories in the
relation-directory. (The last "name"-segment of a link-directory isn't
always thus; in my other email to you shortly I discuss how programs
can sensibly identify the ones that are.) Some other compression is
obviously possible too. It would be possible to create a program (or
an ls option) that worked like ls -P (as described above) except that
instead of printing pathnames through link-directories it would
substitute the corresponding rels entry. And those who really,
absolutely demand to deal with relations via subfile metadata could
create a set of tree operators to simulate it by presenting the
non-relational pathnames of the base filesystem tree as well as
pathnames like this:

/(whatever)/portrait/Dean;(something)/father-son[son]:father
/(whatever)/portrait/Dean;(thingy)/impl-lang/zebra[coder]:lang
/(whatever)/portrait/Dean;(thingy)/impl-lang/zebra[coder]:proj
/(whatever)/portrait/Dean;(thingy)/impl-lang/giraffe[coder]:lang
/(whatever)/portrait/Dean;(thingy)/impl-lang/giraffe[coder]:proj
/(whatever)/portrait/Dean;(something)/friend

. (If (something)/father-son and so on seem rather bulky in this
context, remember problem one from part two; real-world
subfile-metadata names will probably be just as long.)

Other possible things include:

$ cd /(whatever)/portrait/Bob
$ go /(something)/father-son/manticore:son
$ pwd
/(whatever)/portrait/Dean
$ langs-used
pl1 pilot
$ go /(something)/friend
$ pwd
/(whatever)/portrait/Ed
$ go /(something)/father-son/:father
$ pwd
/(whatever)/portrait/Bob
$

.

Using subfile metadata automatically creates a rooted-digraph
representation of the (meta)data: if Mike is the father of Bob, you
express that by using a subfile link to make Bob's photo an actual
subfile of Mike's in the base filesystem "tree". So you can go "down"
the subfile link from Mike to Bob and (maybe) "up" again to Bob. We
saw earlier how we can instead present tree presentations of arbitrary
link-directory metadata. This alternative approach, providing

$ pwg
^Mike-Ted-Todd
$ lsg
Andy

instead of

$ pwd
/(whatever)/portrait/Mike;son-photo;son-photo
$ ls
son-photo employs random-stuff irrelevant whats_this ~ [etc. etc.]

, is more powerful and more pleasant even if all you want is a single
rooted-digraph presentation of the (meta)data you are using. But of
course we don't always want to look at everything as a rooted digraph.
Some data we don't want to present as a rooted digraph at all. Imagine
we have a large body of heavily interconnected /(something)/friend
links , making for a big and definitely rootless graph. We could just
present this as a rooted digraph by arbitrarily choosing one person's
photo to be the root, but we really don't want to have to do this,
just as we don't want to have to choose one person's photo to be the
parent in an individual photo-of-friend/photo-of-friend relationship.
So we need operators to explore and manipulate rootless graphs too.
Something like

$ pwd
/(whatever)/portrait/Ed/(whatever)/portrait/Ed
$ defrel /(something)/friend
# some metadata off /(something)/friend/ is specifying a name-segment
# directory, as with /(something)/father-son/ above, so we do:
$ go Dean
$ rel
Ed
$

would provide the basic "ls" and "cd", and obviously we can do much
more. And one important application of a set of generic rootless-graph
operators is that it gives us a graph presentation of both all
symmetric two-way links (like /(whatever)/friend ) and all asymmetric
two-way links for which we don't have metadata to indicate which role
to think of as the parent.

And naturally data doesn't have to be relational to demand a
non-rooted-digraph representation. Say I attach metadata to the
/(whatever)/photos files specifying for each photo the co-ordinates of
the pictured man's house. Operators which present a geometric rather
than a graph view can then be employed:

$ pwd # current location
/(whatever)/portrait/Bob
$ pwg # current location
^Mike-Bob
$ loc # current location
39° 45.38' N 105° 00.55' W  1610
$ range 5 # everything within 5 kilometres
/(whatever)/portrait/Ed /(whatever)/portrait/Jeff
$ cg Dean # move from father to son
$ up 500; north 20 # move up 500 m and north 20km
$ loc
41° 04.203' N 81° 31.442' W 782
$pwd
/(stuff)/coords/earth/039_56.163N105_00.55W2110/aardvark

. :)

One of the nice things about using rooted digraphs to represent data
is that so many things can be thought of as special cases of them, and
so represented as them. For example, we can sensibly represent a stack
as a tree, with the tail as the root. But of course all trees that
represent stacks in this way have additional constraints: for example,
there is at most one child per parent. So while we can use all the
generic "tree" operators on our stack-as-a-tree, we can also provide
other operators that won't (reliably) work on other tree
representations, including an operator to move to the head and
operators to push and pop. So where possible, we should create
non-rooted-graph presentations of the filesystem by extending the
rooted-graph presentation; we could implement a completely new set of
operators to present stacks and the like, but why do so? Only when the
new presentation can't reasonably be seen as an extension of the
rooted-graph presentation should we make a whole new set of operators;
this is the case with the rootless-graph and geometric presentations
discussed above.

There is also a lot of information that can reasonably be presented as
a rooted digraph but which we may want to present in other ways too.
One example is the base filesystem "tree" metadata itself. In many
ways it's best to think of the filesystem as consisting of files, with
attributes (their (full, opaque) pathnames) attached, floating around
inside their volumes in a completely unstructured fashion. Directories
are basically searches-by-attribute which return an unordered set of
the matching files, with the additional wrinkle that files which have
a more specialised version of the attribute appear in subdirectories.
(For example, all the files with opaque pathname '/usr/[aardvark]' are
children of /usr/, while all the files with the opaque pathname
'/usr/bin/[zebra]' are children of /usr/bin/, despite the fact that
having the pathname '/usr/bin/[zebra]' means that '/usr' is also
asserted of them.) So we need an operator which works like ls/lsg/etc.
except that instead of listing the children of a file it lists all
(and only) its opaque descendants. Beyond that though, you don't
actually much need extra shell operators to support the "bunch of
files searchable by attribute" way of looking at the filesystem; most
of what you need is at the levels above (the visual presentation of
directories/search results in the GUI) and below (using mount() to
expose persistent queries as directories). So it's actually an
untypical, bad example. :)

Speaking of GUIs, the improved filesystem GUI mentioned earlier which
works as a skin over the generic rooted-digraph operators (ch et al.)
can obviously provide a skin over other sets of generic operators too.
For example, it can provide a special GUI representation for stacks,
queues and deques as a thin skin over a set of generic
stack/queue/dequeue operators (itself an extension of the set of
generic rooted-digraph operators, as discussed above). Similarly it
could provide a GUI for unrooted graphs expressed through the generic
graph operators, a 2D or 3D-plot representation of data presented
through the geometric operators, and so on. So it could present a GUI
to the /(something)/friend data that decorates each node with
/(something/father-son and /(stuff)/coords/earth information, or
indeed use a specialised position-on-earth GUI to display the
/(stuff)/coords/earth data of the /(whatever)/portrait files with the
/(something)/friend information represented as great-circle lines
charted between the locations of each pair of friends. The important
point here is how thin a layer this GUI is, knowing nothing about the
syntax or semantics of the data it is representing beyond what it gets
from the operators it supports. This gives it extreme flexibility:
flicking between the two GUI presentations described above, or
replacing the /(something)/friend lines on the globe display with
/(something)/father-son ones, is a matter of one or two commands
rather than recoding GUI components. The power this could afford is
considerable.

And finally, there is the information that we want to be able to view
both as a rooted digraph and as ... a different rooted digraph (or as
more than two different ones). For example, the subfile-metadata
representation of the of the picture-of-father/picture-of-son metadata
discussed above presents it as a descendant chart showing (photos of)
(some of) the descendants of (most obviously) Mike. But parent/child
relationships can just as easily be thought of as creating a pedigree,
giving information about people's ancestors. In other words, it's just
as correct to think of (for example) Joe as being at the root of a
pedigree. Now it happens that the partial pedigrees expressed by our
photo-of-father/photo-of-son relationship metadata are all degenerate
trees, but that's only because everyone has only one father. Bring
mothers and daughters into the picture as well and the answer to
"which way is root?" becomes entirely relative, no pun intended. So we
might want to be able to view parent/child (in the biology sense)
relationships both as descendant charts and as pedigrees. This is easy
to do using the link-directories approach: just tell the "tree-view"
operators to regard :son rather than :father as being the rootward
role, or vice versa. (Note that we can do something similar with
rootless graphs: specify a root node using a command like

$ setroot /(whatever)/friend/Ed

and then you can use the rooted-digraph operators on the graph.) But
the subfile-metadata approach only provides us with one presentation
or the other unless we duplicate or rejig the data, or use a custom
persistent query.

In sum: "file-as-a-directory" gives us nothing, in terms of power,
unambiguousness, or convenience, that we can't get from
link-directories plus a small set of convenience utilities. The
reverse is emphatically not the case. Furthermore, link-directories
plus some more convenience utilities give us powerful things that are
pretty much beyond the ken of "file-as-a-directory" altogether.

But why not build the new tools to work on top of subfile metadata
rather than link-directories? Firstly, because subfile metadata is not
a sound foundation to build them on. Due to things like problem five
in part two and the problems with symmetric links above, subfile
metadata is ambiguous and sometimes downright misleading, so the
amount you can safely infer from it without extra context information
is limited. Secondly, once we have implemented the tools - once we
can, for example, present the ;son-photo subfile metadata as a
pedigree using the rooted-digraph operators and use those operators to
navigate and tweak the pedigree just as easily as if it were expressed
in the base filesystem tree - the advantages of using subfile metadata
are gone. The ;son-photo links give us a rough-and-ready tree
representation of the descendant chart for free, but we can get a
better, cleaner tree representation of the descendant chart using the
same class of operators we use to navigate the pedigree. So why put up
with the pain that the file-as-dir kludge will cause us when it no
longer satisfies any of our needs? Providing both file-as-dir and
link-directories is a bad idea too, for roughly the same reasons.

> - Alex
>

Leo.

--
Leo Richard Comerford - http://www.st-and.ac.uk/~lrc1 - accept no namesakes :)

Reply via email to