Based on what I have been reading about the Liskov Substitution Principle, I understand that a square and rectangle class cannot be a part of the same inheritance tree.
I would like to apply these ideas to a Folder and a File, as they commonly exist on disk. Is there a property of one or the other or both which would force a conclusion they too should not be part of the same inheritance tree according to Liskov?
What are some properties we could consider?
The data. Files consist of bytes. However, Folders can be considered to consist of the bytes of the files they contain.
Access to both is defined by permissions
I suppose the property where inheritance breaks down would be one concerning containment. A folder contains files. A file does not. However, if one considers that a file is just a collection of bytes, then a folder could be considered to be just the collection of bytes consisting of the files in the folder.
Is there a property of a file or a folder that requires us to maintain two inheritance trees?
2 Answers 2
The "substitution" from LSP does not mean that the subclass ultimately behaves same as way the super class. It cannot do it always anyway, simply because it is another class.
What it does mean is that the contract which is important to the code it is being injected to does not change. So, for the Folder and File there are a lot of common:
- Both have parent directory
- Both have name
- Both may exist of not
- Both have permissions and ownership
- Both can be moved, copied to another directory
- Both can be renamed
- Both can be deleted
So for a code which only uses the properties and methods, you could substitute one with the other without violating the LSP.
The data. Files consist of bytes. However, Folders can be considered to consist of the bytes of the files they contain.
This is rather unorthodox, I believe it would not be reasonable to do so. Though I remember in some Unix-like OS I could read a directory as a text file which were listing files.
-
Is it unorthodox enough to conclude that folders and files should not be considered part of the same inheritance tree? I cannot imagine having a folder and not have an interface that would try to access files contained within it.ericg– ericg2020年03月03日 02:29:26 +00:00Commented Mar 3, 2020 at 2:29
-
@ericg more realistically there would be some
FilesystemEntry
which bothFile
andFolder
inherit.max630– max6302020年03月03日 06:02:20 +00:00Commented Mar 3, 2020 at 6:02 -
A lot of those common properties aren't really common for certain corner cases. For example, a file must have a parent directory, a directory may have one; a deletion operation can be performed on both, but different errors can occur, which makes the contract slightly different.Christian Hackl– Christian Hackl2020年03月03日 06:59:22 +00:00Commented Mar 3, 2020 at 6:59
-
@ericg Just as in the composite pattern: the component interface exposes child access functions, but leaf nodes just behave as if they had no children. No LSP issue if you formulate preconditions, postconditions and invariants accordinglyChristophe– Christophe2020年03月03日 07:44:50 +00:00Commented Mar 3, 2020 at 7:44
If you are creative enough you can make one descend from the other and satisfy Liskov. But you would have to bend semantics, like with square and rectangle. And that would not benefit your model or make it easy to work with by folks who have a good understanding of what a square, a rectangle, a file or a folder is.
You could argue that a square is a simple rectangle that has 4 sides with just one side length specification x. Then rectangle could descend from it and have an additional side length specification y. Then if you treated a rectangle like a square you would be OK. Whenever you draw it you would just use x for all four sides and that would make a square.
But that would be a technical trick to make ends meet without making much sense and it is the same with files and folders. If you take meaning of properties into account (rather than just treating them as variables that may have different meaning depending on the context), this would fall apart. A good model is serious about semantics, if it is not it will be a pain to work with. So whatever the answer to your question is, you should not be smart just to fix something that does not fit naturally.
Explore related questions
See similar questions with these tags.
draw(location)
, and if that's all you need in your abstract interface, then it's fine. In other words, it's not some universal property of rectangles and squares that results in a violation of Liskov SP, but what the base type is defined to be, and what its methods mean and how they are expected to be used.