It would be nice if KotlinX IO had something like ...
# io
j
It would be nice if KotlinX IO had something like this so I don't have to pass FileSystem and Path around together everywhere.
👍 1
k
This kind of conflates what's a services and what's data, which in my opinion makes Java's various IO libraries so painful to use.
Particularly the companion
temporary
function has a hidden static dependency on the system file system which is really difficult to use under test.
j
That's because at the moment, KXIO has
SystemTemporaryDirectory
which AFAIK only applies to the
SystemFileSystem
.
Also, I think Java's baseline
File
was in many ways much better to use than the follow up
Path
specifically because I can't meaningfully use a
Path
without a file system attached anyways. This combines the best of both worlds, making a nice syntax while enabling the use of multiple file systems. The only thing I really don't like about it is
atomicMove
, which can crash due to poor usage by the user.
I think, however, that just means that function isn't a good one in particular and should change. That doesn't mean the core idea of providing a combined class doesn't make sense.
m
Another way of dealing with this problem would be to do what UNIX systems do. You have one program wide global file system and you mount all other file systems in that. The global file system is a singleton then by definition and you don’t have to pass it along with every single path because the local file system is then encoded in the path already.
1
j
Another thing that could be done is removing the default from the constructor and encouraging the use of the below instead:
Copy code
val FileSystem.root: KFile get() = ...
SystemFileSystem.root.path("opt", "myprogram", "data.csv")
m
In my comment above I missed the fact that you explicitly asked for KotlinX IO. My comment refers to Okio which actually has various FileSystem implementations right now already and KotlinX IO doesn’t.
j
Eh, they're close enough the same thing. KotlinX IO is so clearly based on Okio. I actually was originally going to just go use Okio figuring they probably had something like this already, and made this instead when I found out the didn't. I look at KFile as similar to a
ZonedDateTime
wrapper I made for KotlinX Date. It's just a convenience wrapper for moving data that is clearly associated around and doing operations that require both. I wouldn't ever suggest removing
Path
and
FileSystem
in favor of this. This is just supposed to be a convenience and readability improvement tool.
k
The author of Okio has a blog post that touches on this: Identifiers aren't Services. It even touches on the specific
java.io.File
and
java.nio.Path
examples.
j
There's an HTTP client hiding in the URL class. When I call openStream(), that client is prepared and put to work. I don’t like being cut out of that setup! Ican't dependency-inject my own configured instance for production or a fake in a test.
It's not hiding in
KFile
. It's directly accessible and it can be controlled. If the argument is that there should be no default file system in the constructor, I can agree with that. In fact, I'll go change the definition in the snippet. Creating a
KFile
now looks like this:
SystemFileSystem.root.path("path", "to", "my", "file")
I might write an Android app that sends its collection of cached images to the server as a List<File>. My server could call File.delete() to free up space on that Android device, but that's not what would happen!
KFile
isn't serializable, so no, you couldn't send it any more than you could send
FileSystem
. In addition, with the removal of the default file system in the constructor, it's clear to the user that you can't just use a
String
to represent this type.
Subclassing
File
is another thing you could do, but shouldn’t:
KFile
is a final, transparent tuple of a separate identifier and service. In short, I don't think any of the arguments made in the blog apply, at least not with the change I just made. In addition, I think keeping
Path
and
FileSystem
separate in common usage actually has a different set of dangers - namely, accidentally using a
Path
with the wrong
FileSystem
! When moving them around in code, they should remain bound together. If you don't, you either have to have the discipline to pass them around together every time and keep which one belongs to which straight or - more likely, if you have junior devs - you'll end up having a bunch of functions just use
SystemFileSystem
hardcoded that need all of their headers changed.
m
With any luck we'll be getting a NIO
Path
-like design as opposed to Okio's design.
👍 1
i
At least the root should be roots. For example we have manu roots on Windows. Not only the
A:
B:
C:
and so on, but also the
\\server\hostname
and even the
\\?C:\
(I don't think we should hide the complexity to the user, it will make them failed when they need the platform string representation.).
Personally I want to know is it valuable to fix and enhance the current implmentation? If not, where I can find the latest design or plan so I can contribute my code. I don't want to write my own limited implementation and then serval days passed I found there's an official implementation...
j
Either that or we could represent the various roots in windows as basically
/C/Program Files/whaterver
Not sure what makes more sense. I just need something standard to use for my library so that I'm not hurting adoption with non-standard API exposure. I'm no file systems expert
i
@joseph_ivie No, if you represent Windows path in non-windows style, the user will get hurted when they try to
exec("notepad.exe", txtPath.toString())
The Path object is platform dependent, it should be represeted in platform specified way.
And, the
/C/...
can be also treated as
<CUR_DRIVER>:\C\...
Boom. So in my PR I remove any calls to MinGW and replaced them with Win32 API. Here's Windows, not POSIX compliant.
j
I think
Path
should be a platform-independent strictly data-class concept, and I really really really don't want
toString()
to depend on the current platform, since at least in the current design,
Path
could be used to represent a path on several different file systems, each of which may have their own string rendering. You might be on Windows, but if you are using a
FileSystem
that represents a remote HTTP/REST based file system or some other form of remote file system, it doesn't really matter what Windows thinks the path format should be. I think `KFile`'s
toString()
could support that case, however, since we would know what
FileSystem
is being referred to and what textual representation it uses.
Perhaps the different drives should be different file systems?
This also has me thinking that perhaps
KFile<FileSystemType>
could actually be really good to explicitly restrict inputs to using local file systems in some scenarios?
i
I get it. But I don't think it's possible, at least it's very difficult to achieve. That means you need to design an universal path format, another URI. And of coursely, you have to make a detailed specification to describe how to translate the universal path between the platform format. @joseph_ivie
j
That's why I think overall it might just not make sense to have
Path.toString()
intended for use with tools as a whole - heck, I might even deliberately choose its string representation to be something like
[path, to, thing]
just to prevent people from making assumptions that
toString()
could be used safely that way.
You're right,
KFile
probably can't have a
toString()
for that reason.
i
OK, the toString() can be removed. But the problem is not changed, do you want a universal path format?Even it cannot be represented in string. If you want, you will facing the platform mapping problem.
Java
java.nio.file.Path
gave up to the problem, they represents all path in platform format...
And personally I have a question, why you create another
file://
?
j
URI already exists, so yeah, let's not make another standard there. It would be the closest thing to a sensible
toString()
for
KFile
. When you say "the problem" you're referring to the use of
KFile
or
Path
or whatever else in a practical setting with the command line or system tools, right? I think that having an explicit
toPlatformString()
that applies only to
KFile<SystemFileSystem>
would make a lot of sense, but really, even that seems imperfect. The only truly safe thing I can think of would probably be to have the CLI or process running tool have its own conversion function for converting a
KFile
or
Path
into a string for usage.
In an ideal world I see
fun exec(vararg args: KFile<SystemFileSystem> | String)
or something like that being a good function header, but we don't have union types
i
Not only for String representation. Even there's no string representation, You MUST consider how to store the universal path. @joseph_ivie
j
What I would give to force rename the entire Java ecosystem's
toString()
to
toDebugString()
or something like that.
List<String>
under the hood of Path is probably the closest to both making sense and being universally compatible, but even then that makes
..
and
.
kind of strange.
kotlinx.io.Path
isn't attached to a particular file system - to attach it, I recommended
KFile
which is the class at the top of this thread.
I hesitate to recommend a list of a sealed class just because that's obnoxious, but it's probably the most correct in terms of types
roughly
List<String | ParentFileReference>
perhaps
i
Here's Windows paths, your store must be able to distinglish them:
\\?\MY_LAPTOP\shaRe\foo
C:\shAre\foo
\share\foo
fOo
You're also have to consider how to handling the equality(case sensitive or insensitive). I'm still not refer to dot and dotdot.
j
Indeed, which is annoying - some systems care, some don't. To this day that causes grief for multiplatform stuff in my experience
i
So I think rather to design a cross-platform path representation, it's better to make a specification about how to convert them to URI. At least URI is well-known.
But, personally, I have no opinion about combine or not combine the Path and FileSystem...
No, I'm wrong. If the Path is platform dependent, it should be combine...
j
agreed; I don't want to mix up their usage scenarios. Goodness knows I've messed up code using Java's
File
with platform compatibility more times than I can count.
i
Now my code only use
java.nio.file.Path
. No string representation except I have to I/O the path...
j
Yep. Strings are dangerous when it comes to talking about
Path
and
File
and whatever else. These days I work hard to make sure they don't go in or out of string representation wherever humanly possible