Most filesystems on today's PCs date back to filesystems originally developed for floppy disks. Even modern filesystems like Windows NT's NTFS are not fundamentally object-oriented. I have a specific meaning in mind for this over-used term: a filesystem should define the relationships among files, including the differences between code and data. An object-oriented filesystem such as the one described in this Ideafile can provide many significant advantages over conventional filesystems.
The key to this idea is raising the level of abstraction for familiar concepts like programs, documents, and folders. There should be only two types of concrete objects in the filesystem: Code objects and Data objects, and these differ only in the sense that Code objects contain executable code. All higher-level objects are synthesized from these: a Program is a collection of related Code objects; a Document is a collection of related Data objects. An Application can include both Programs and Documents.
By way of comparison, today's applications like Microsoft Word consist of many files: "executable" files that include elements of both code and data, linkable library files similar to this concept of Code objects, and documents like these Data objects.
To explain the potential advantages of a pure object-oriented filesystem, I'll describe how Code and Data objects are stored, combined, and used.
Code objects in the proposed filesystem are much smaller than today's programs. The best analogy is to a complex subroutine, something that performs a specific function on a specific type of Data object. This is similar to the classic object-oriented programming concept of a "method".
The essence of a Program in this filesystem is that a Program consists of all of the Code objects that can operate on a specific type of Data object. Here we arrive at one of the interesting differences between this proposal and conventional filesystems. In conventional filesystems, a program is a single file. If multiple programs in a system can perform identical functions on identical data objects, today's PCs have multiple copies of those functions, one in each program file.
To eliminate this wasteful redundancy and encourage reuse of software components, we will have only one instance of each Code object in each system. Programs incorporate Code objects by reference. In this way, a Program is really nothing more than a list of references to Code objects.
Like Code objects, Data objects are individually simple. A Data object could be a few pages of plain ASCII text, a GIF image, or even as simple as a single URL.
Documents can be as simple as a single Data object, as with a simple text file. On the other hand, a Document can be like a Web page, with multiple embedded images, or like a book, with multiple chapters. Each independent element of a Document is stored as a separate Data object. This allows multiple Documents to incorporate a single Data object by reference, much as Programs can share Code objects.
An Application is a set of Programs that can perform specific functions on various types of Data objects, and a set of Documents that may include help files, templates, and so on. Another difference between Programs and Applications is that Programs do not have a user interface. A Program simply performs a function; Applications give the user some way to determine which functions to perform on which Data objects.
Note that the system user interface itself acts as an Application, and may allow the user to direct that some Code object is to be executed against some Data object. This only makes sense for Code objects with a clearly-defined function, such as inverting an image. In this way, we can provide a graphical equivalent to the Unix command-line redirection function. (Of course, we could provide a command line on an OS with this type of filesystem, too.)
Obviously this plethora of objects means we need a good mechanism to keep track of them. I propose using 64-bit Object Numbers to refer to each object. Object Numbers are generated randomly at the time the object is created. Each Object Number has meaning only on the system where the object is created, and systems are responsible for preventing collisions in the Object Number space. As objects are moved from one system to another, Object Numbers are regenerated. In order to keep objects coherent between systems, each object must include a reference to the original system and Object Number.
This requires another kind of number, one for each system: the System Number. These numbers are also 64 bits long and generated randomly, at the time the system is manufactured. The chances of a collision in this number space is very small, but it would be desirable to provide some mechanism to verify that System Numbers are unique.
This, in turn, gives us the chance to introduce another pair of related concepts: Object IDs and System IDs. These are fully-resolved IDs, valid globally, validated by some certification authority. They also act as Object Numbers and System Numbers. The object or system must carry within it the certificate that specifies the certification authority and some independent mechanism to identify the object or system.
For objects, this is accomplished through a 64-bit hash of the entire object. This number, which will include the code or data in the object as well as the identification of the certification authority, proves that the object has not been modified since the Object ID was generated. For example, Code objects from Microsoft would carry a certificate from Microsoft. The Object ID for the Code object can be used to prove that Microsoft has certified exactly this Code object, and that it has not been tampered with.
The System ID is unique for each system, and certification can be based on URL, IP or ATM address, or any other mechanism. In this sense, System IDs will work like VeriSign's site certificates.
When installing a new object (Code, Data, Program, Document, or Application) on a system, there may be some overlap between Code and Data objects already installed, and those to be installed as part of the new object. By examining the System and Object Numbers, the target system can identify duplicate Code and Data objects, and simply not re-install them.
An interesting issue comes up when a Code object is upgraded to include new capabilities, or a Data object is revised. Here, the previous Object Number is only re-used when the new object is a complete superset of the previous object, capable of performing every function of the previous object. The only allowable changes to Code objects would be include bug fixes or expanded functionality. For Data objects, changes might include corrections of typos in text, minor retouching in images, etc.
The key issue here is whether the new object will perform equivalently to the old object it replaces when used with older Programs and Applications. I have to say here that I don't think this is going to happen very often. If an object is changed, it should probably be given a new Object Number so that when it is installed in a target system, both the old and the new objects exist together.
One of the best improvements made possible by this filesystem design is a dramatic difference in the way files are presented to the user. The primary presentation will be based on Programs and Documents, as with today's systems. However, the user interface can also present Applications as a single icon that represents the entire set of objects in the Application. It can also provide a detailed breakdown of the individual components of an Application, Program, or Document if the user wishes to see one.
Since the filesystem is keeping track of which objects belong to each higher-level construct, it can intelligently manage additions and deletions of objects. If the user attempts to delete a critical Code object from a Program, the user interface can gracefully decline to cooperate, or at least inform the user that this act will disable that Program. If the user wishes to extend the functionality of an Application, simply dragging and dropping a Program item onto an Application icon will accomplish that result.
Some Data objects will contain code of a type which cannot be directly executed. Since these Data objects require associated Code objects to interpret or recompile the code, they cannot be considered to be Code objects themselves. Instead, we call them Active Objects. These could include Java applets, Visual Basic code, or anything else of this type.
The filesystem should manage compression on a per-object basis, with multiple compression mechanisms designed to suit different types of objects. This compression should be transparent to most uses of objects, so that functions like object hashing are performed on the uncompressed versions of the objects. The compression functions themselves will be implemented in Code objects, of course, but these Code objects will be invoked under the control of the filesystem and not under the control of Applications.
A special case of compression is the mechanism for storing graphics objects. There should be only a few basic formats for image storage: RGB 8:8:8, YUV 4:2:2, etc. Applications will generally act on these formats. The actual storage of graphics objects will go through the filesystem-managed compression process, with the choice of codec managed by the Application that created the graphics object. In this way, the whole issue of supporting GIF, JPEG, PNG (no relation) and other image formats becomes invisible to most applications.
Files in today's PCs are much larger than the objects I am describing here, and there's a good reason for this: most of today's filesystems use relatively large allocation units to keep pointers short. I think it's time to give up on this strategy, and Windows NT's NTFS is a good demonstration of how to do it. Objects can be very small, so I believe the standard allocation unit should also be small, perhaps 256 bytes. This requires us to use large pointers. 32 bits should be the smallest pointer size, with up to 64 bit pointers possibly required by future systems.
Locating an object on the system boils down to translating an Object Number into a device ID and a pointer. This should be done in parallel by all devices, breaking today's fixed connection between what an object is and where it's physically located. Once an object has been located, of course, the Application using it can keep track of the device ID and pointer to speed up repeated accesses. There must be some mechanism allowing the system to change the location of the object and communicate this change to Applications. This permits optimization of distributed systems.
Home | Ideafiles | Opinion | Toscana | Photography | About the Author | Sitemap
If you have comments or suggestions, please email me at png@ideaphile.com.
All content copyright 1996-1999 by Peter N. Glaskowsky. All rights reserved.