On 2009-Aug-15, at 9:22 am, Jon Lang wrote:
IOW, your "outside the file" stuff is whatever can be done without
having to open the file, and your "inside the file" is whatever only
makes sense once the file has been opened. Correct? If so, could you
give some examples of how such a distinction could be beneficial, or
of how the lack of such a distinction is problematic?
Well, I definitely think there needs to be a class that combines the
inside and the outside, or the data and the metadata. Certainly the
separate parts will exist separately for purposes of implementation,
but there needs to be a user-friendlier view wrapped around that. Or
maybe there are (sort of) three levels, low, medium, and high; that
is, the basic implementation level (=P6 direct access to OS- and FS-
system calls); the combined level, where an IO or "File" object
encompasses IO::FSnode and IO::FSdata, etc.; and a gloss-over-the-
details level with lots of sugar on top (at the expense of losing
control over some details).
In fact, having q, Q, or qq involved at all strikes me as wrong,
since those three are specifically for generating strings.
Pathnames still are strings, so that's fine. In fact, there are
different things going on here; one is to have a way of conveniently
quoting strings that contain a lot of backslashes. Just as Perl lets
you pick different quotation marks, to make it easier to quote strings
that have a lot of " or ' characters, so it should have a way to make
it easy to quote strings with a lot of backslashes. (The most obvious
example being Windows paths; but there are other possibilities, such
as needing to eval some code that already has a lot of backslashes in
it.)
Now, you can already turn backwhacking on or off via Q's :backslash
adverb; Q:qq includes :b (and Q:q recognises a few limited escape
sequences like \\). So you could say Q[C:\some\path], and you could
add scalar interpolation to say Q:s[C:\some\path\$filename]. But
there's no way to have all of: literal backslashes + interpolation +
escaped sigils.
Perhaps instead of a simple :b toggle, we could have an :escape<Str>
adverb that defaults to :escape<\>? Then you could have
Q:scalar:escape("^")[C:\path\with\literal^$\$filename].
The ultimate in "path literals" would be to establish a similar
"default delimiter". [...]
`path`.size # how big is the file? Returns number.
There's something that slightly jars me here... I don't like the
quotation returning an IO object. (I like the conciseness, but
there's something a bit off conceptually.) Let's see, `exec command`
bugs me too -- it's quoting something and then doing something with
the quoted string. (It's not entirely unreasonable as a cryptic
shorthand in the shell, but I think P6 should have an actual command
for that (e.g. the proposed run-gather()).) Similarly, in this
example, we're quoting a pathname, and then creating an IO object from
it.
So I don't like the quoting-and-then-using, when done by the quotation
marks, although having a function (really, macro) that does its own
quoting seems fine: "io /some/autoquoted/filename". And /regex/
doesn't bother me either. Hm. Ah, but an instant regex isn't doing
anything besides creating an object -- it is comparable to q[foo]
creating a Str. So `exec me!` bothers me because it isn't just
returning some kind of "System::Command" object, it's more like
creating the object and then calling the .run() method on it too. /
pattern/ doesn't *do* anything with the regex.
Now, isn't Q:path[/some/file] just creating an IO object? Unlike /
foo/, where "foo" just IS the pattern, "/some/file" is *not* an IO
object, it's just a filename. So if the special path-quoting returned
an IO::File::Name object, I would be perfectly happy. But you can't
have $filename.size -- a fileNAME doesn't have a size, the file itself
does. To get from the filename to the file, you need another step,
and it's that extra step I don't like being hidden inside quotation
marks, just as in the `exec` case.
Anyway, that's a subtle but important point, I think. Fortunately, in
the end it doesn't have to work out much differently: instead a "path"
quoter that does IO-stuff, have a "path" function (macro, whatever)
that does quoting stuff.
$file = new IO::File(FSNode => "/path/to/file");
$file = path "/path/to/file";
$file = io /path/to/file;
$file = file://localhost/path/to/file;
Incidentally, I do think it's worth having an actual File::Name type,
even though names are really just strings. For example, not all
strings are valid filenames if the FS doesn't handle Unicode.
However, Strings should get transparently cast to IO::Names wherever
possible, so the typical user would never have to notice the difference.
IO::Name objects also provide a way to concatenate items correctly, as
per Hinrik's original post regarding a better way to do
File::Spec::catdir. I completely agree that we should encourage use
of the official way to join paths, and using catdir() everywhere is
too verbose, and simply leads to people doing "$dir/$file" anyway.
But I'm not keen on using a variation on qw// that splits on
whitespace; spaces aren't that uncommon in filenames, and look
unnatural to me as a path-separator. However, an infix:</> operator
on IO::Names would allow nice, simple, and familiar expressions like
$path/$file.
The objects would have to be IO::Names, not Strings, though it should
work with IO::FSNodes or whatever (delegating to their .names), and
infix:</>(IO::Name, Str) should probably also work. That means at
least the first operand has to be an IO object, which can easily be
done even if you have only strings to work with by:
my $output = io $dir/"output.txt"; # where $dir is a Str; io
$dir generates the object
my $output = path $dir/"output.txt"; # or this, if we have
path() rather than io(), etc.
On the other hand, Str "/" may be officially OK as a path separator,
so that {join "/", $dirstring, $filestring} will work, assuming that
we can require IO objects always to parse a literal string the right
way. (I.e. "/" is made to represent the official cross-platform path
separator. Unless you parse some literal text with Q:ntfs, which
parses a literal "\" as "/"?? Or say "use path-separator '\';" or
something!)
In fact, path literals may be more pattern-like than string-like, when
and if you start taking wildcard characters into account:
if $file ~~ path[./*.txt] {
say "$file is a text file in the current working directory."
}
Is that just a regex, in fact? Or to allow for special quoting,
Q:special-path-adverbs:regex? In other words, certain IO functions
would be able to take a regex instead of a string for the Pathname
arg, and return an array of however many items matched.
Though, to speak of file-types, this particular example would I think
better be handled by:
if $file.type ~~ MIME("text/plain") {...}
or just:
if $file.type ~~ "text/plain" {...}
since .type() presumably returns a Data::Type::MIME object to begin
with. (Or even better, a Data::Type::UTI object, since UTIs are a
more useful superset of MIME. Is there any system that would be even
better than UTIs?)
<http://en.wikipedia.org/wiki/Uniform_Type_Identifier>
<http://developer.apple.com/documentation/Carbon/Conceptual/understanding_utis/understand_utis_conc/understand_utis_conc.html
>
-David