xoofx / zio

A cross-platform abstract/virtual filesystem framework with many built-ins filesystems for .NET
BSD 2-Clause "Simplified" License
817 stars 61 forks source link

Extract a IReadFileSystem from IFileSystem? #1

Closed xoofx closed 7 years ago

xoofx commented 7 years ago

Derivation from a suggestion from @Porges on twitter

Original idea was to extract read methods from IFileStream to a IReadOnlyFileSystem and derive IFileSystem from it... but I'm not sure I like the idea that IFileStream is inheriting from IReadOnlyFileSystem as it would imply that casting to this interface would guarantee that the underlying filesystem is readonly... which maybe not...

So instead, scratching the idea of:

Thoughts?

xoofx commented 7 years ago

Thinking more about it, not sure it is worth the troubles that this idea is bringing...

First, IFileSystem.OpenFile is partially readonly depending on its arguments values (e.g FileMode.Open), so making this method available on IReadFileSystem would make it quite unbalanced with the supposedly "read" behavior of the methods in this interface...

Secondly, it complicates inheritance and C# OOP options are not great in these cases (no multiple interface implementation inheritance via mixins). Introduction of ReadFileSystem would require doubling the ComposeFileSystem into a ReadComposeFileSystem, but the ComposeFileSystem could not inherit the behavior of both abstract FileSystem and ReadComposeFileSystem. Leading to duplicate implementations...

I think that the current usage of ReadOnlyFileSystem while not an interface already covers the usage of exposing a readonly filesystem by contract... based, on the concerns above, not sure we really need an interface here.

xoofx commented 7 years ago

Closing for now. If anyone has strong arguments/use-cases for this (that would address my concerns), we can discuss and reopen it.

abatishchev commented 7 years ago

Hi, I would go with interface inheritance due to its design elegance. One always can hack in one way or another, upcast is only one of the options. Reflection is another, and here not much you can do about. Same case basically in many other places in .NET, including BCL. Can you implement implicit/explicit cast operator which will return either a wrapper, or throw exception if you really want to prohibit this?

abatishchev commented 7 years ago

In general, i prefer interfaces over base classes and fallback to the latter only as last preferable option. The Composition over Inheritance Principle echoes my sentiment :)

xoofx commented 7 years ago

Hi, I would go with interface inheritance due to its design elegance.

It depends. Too many interfaces can lead to design ugliness, less practicability, barrier adoption due to unnecessary complexity...etc. 😉

As I explained above, I have one primary concern for splitting the interface is the IFileSystem.OpenFile method, which is both readable and/or writeable depending on its arguments. Unlike other methods, its behavior is mixed.

We could start to split the methods with a IReadFileSystem.OpenReadFile(path, share) but we would still have in IFileSystem.OpenFile(path, mode, access, share) where mode could be read. And things start to smell bad... like how to enforce the behavior that OpenFile must call OpenReadFile if mode == Read?

I don't see a clean way to handle just this method.

I'm also not thrilled to introduce an interface split for one type of behavior. Opening the pandora box, and this could lead to split even further for a IDirectoryFileSystem IFileFileSystem IMetadataFileSystem ISearchFileSystem and of course, then introduce a split here, because we want to separate read from write... so double the number of interfaces... this would become ridiculous...

Having a single entry point IFileSystem interface makes Zio quite straightforward to handle and understand. I would like to keep this simplicity as much as possible.