Copyright (C) 2002-2003
Sebastian Reichelt
First Publication: December 29, 2002
See History.
Object-Oriented Programming (OOP) was invented quite some time ago and is currently the favorite way of managing large projects and increasing maintainability and scalability. Object-oriented principles have been applied to a few other areas, including databases and hypertext, but currently there is no implementation of a general object-oriented system, which unifies these principles under a common roof.
This proposal aims at implementing such a roof in the shape of an operating system using classes and objects to describe all of its components. This operating system can be implemented on top of other systems; this approach reduces the time needed to create it and opens it to a greater amount of end users.
Typical operating systems organize their data in "files". Files are octet streams accessible via an identifier known as the "path". The "type" of the file is usually included in the file name and therefore in the path; parts of it may also be included in the file data itself (for example, there may be several incompatible file formats to describe the same type of contents). An object-oriented system will talk in objects instead, each of them being instances of a class. A "file" corresponds to an object, which can encapsulate one or more other objects. The "type" of the file is the object's class. Objects are accessible as items of lists or via single object references.
Objects can reside on a disk (as files in the underlying system) or in memory (see Object Storage). They can be modified through their properties, regardless of where they are stored. The main difference between objects and files is that objects have a common format. If the class of the object is known, it can be accessed transparently. An object editor can use the object directly, so that the operations of the editor are also transparent to the user (see Object Editors).
This concept is new and unseen because current operating systems are, in a way, procedure-oriented. They usually operate on raw binary data; object-oriented extensions are only implemented in individual programs. Unix systems use command-line tools to operate on the data, which is the exact opposite to an object-oriented view: Both input and output data are raw; there is nothing which classifies the contents of the data. The user needs to know about the format him-/herself. The command-line program is not related to the format of the data either; it is just a tool with a name. In Windows, there is at least an association between file types and programs, but this association is very limited and not transparent. In fact, a file, its format, and the code which deals with the format all belong together, and OOSys honors this.
For a list of actual benefits, see Benefits of OOSys.
As noted in Introduction, objects can be stored in memory or on disk. To achieve the maximum possible transparency when storing objects, the different existing media types need to be classified:
Type | Examples | Capabilities |
---|---|---|
Read Only Memory (ROM) | ROM chips, CD-ROMs, DVDs, Compressed Data | When writing to ROM, OOSys should force the user to create an archive of objects at first, then write this archive to the medium. This ensures that no resources are wasted. |
Rewritable Read Only Memory (ROM) | EPROM, Flash ROM, CD-RW, Compressed Data on a rewritable medium | Even though in theory, this type of ROM could be treated like RAM, in practice this should not be done, since write access can be slow and/or wear out the medium. In particular, changing the properties of objects directly should not be permitted. |
Random Access Memory (RAM) with fixed size | The computer's RAM, hard and floppy disks, tapes | OOSys should implement its own memory allocation system to deal with this type of memory, then operate on it as Dynamic RAM (see below). To avoid fragmentation, OOSys can either load all objects into another medium and write them back, or it can provide a defragmentation system. |
Resizable Random Access Memory (RAM) | Allocated blocks of memory in the system RAM, files | No special treatment is needed. When the memory allocation system needs more space, it will grow the memory block accordingly. |
Dynamic Random Access Memory (RAM) | The computer's RAM, disks | Dynamic RAM represents all media for which the underlying operating system already provides a memory allocation system. This system should be used in cases where this is the best solution. In most cases the allocation system for the RAM is sufficient for OOSys (but not always; for example it might place a limit on the number of allocatable blocks). OOSys should also use the file system on disks to some extent, but it should not allocate a file for every block of memory it requires. |
Sequential Access Memory | Tapes, disks, files | Some media are optimized for sequential reading or writing. This restriction should be taken into account when implementing the object format, but there is probably not much to optimize. It is possible to implement a buffer for reading and writing, but disks already contain such buffers in the hardware. |
To sum up, all types of Random Access Memory (RAM), including files, can be accessed similarly through different layers. This makes in-place editing of objects stored in files possible.
If all objects are really considered equal, they also need to be able to reference each other regardless of where they are stored. The following table shows how items in different media are usually referenced:
Medium | Reference | Fault-Tolerant |
---|---|---|
System-Managed RAM | Handle or starting address of a block | No |
File | File path (absolute or relative) | Yes |
Part of File | File path (absolute or relative), ID | Yes |
Network Location | IP address or host name, port number, path | Mostly |
"Fault-tolerant" means that objects which have been deleted or are unavailable may not cause system errors or data corruption. Network locations are not fully fault-tolerant since a deleted or unavailable location might not directly cause an error message in return, causing the access to hang for a while. However, this is not critical, and special care can be taken to allow for user interaction in this case.
"Part of file" refers to an object inside a file, if the file contains multiple objects. If objects inside a file are referenced via an ID (pseudo-random or incrementing), deleted objects can be detected immediately, so this method is also fault-tolerant.
Interestingly, the most popular way to store objects, that is, inside of system-allocated blocks of memory, is the only unsafe one. If a reference to such an object breaks, the result is system-dependent and almost unpredictable. Since OOSys is meant to be a very modern system in which users do not know about critical errors such as segmentation faults, it needs to ensure that references to objects in RAM never break.
If the reference comes from the same medium (or at least from a medium with an equal life span), it is enough for the referenced object to know about the reference and keep it in a list. When the object is deleted, it clears all of these references. However, if OOSys is terminated in an abnormal way, the objects stored in RAM are deleted, but references from other media to the objects may still exist. Luckily, such references are rare. This allows for an easy solution: OOSys must maintain a list of such references on a hard disk, clearing all references when the system starts.
Objects stored on removable media may not contain any references to objects on media which are not fault-tolerant. The same is true for objects transferred over a network. The references should be cleared by OOSys when transferring objects, but if the objects are transferred by the underlying operating system (by copying or transferring files), OOSys on the target system needs to notice this and quietly remove all such references. This can be done by archiving all OOSys files inside OOSys.
In all other cases, the references may simply stay active until they are used, and then be deleted when OOSys notices that they are no longer valid.
Before the object format is dealt with (see Object Format), you already know about the one most important feature: the class reference. Every object needs to contain the identifier of the class it is an instance of. Since objects may be passed around, the class reference must be valid globally. To ensure this, a few different types of classes must be distinguished:
Type | Explanation |
---|---|
Globally Registered Class | There should be an OOSys class server at a fixed location (with mirrors and everything which can ensure reliability). Classes can be registered on this server and are downloadable from it. Clients can also download a list of all new classes, including their full IDs, names, and possibly a description. With this information, a class can be downloaded as soon as it is needed, and users which obtain objects from a floppy disk or network location immediately know the class names of the objects. Different versions of the same class may exist, but they must be compatible in both directions. This means that properties and methods may be added and removed; however, the types of properties may not be changed. Obviously, a registered class may only reference other registered classes. |
Locally Registered Class | OOSys should implement the possibility to specify several custom class servers. For example, databases contain custom classes which should not need to be registered globally; they are unregistered classes as described below. However, users should be able to download them manually, and the same restrictions as to globally registered classes should apply (see Database Extensions). |
Development Class | Classes which are still under development but meant to be registered are somewhat special. Only a single flag should be used to distinguish them from registered classes. This means that development classes need to be registered as well, as soon as their development is started. Everything else is still permitted. Objects which are instances of a development class need to contain a magic number of the class, which should change whenever a change in the class makes it incompatible with a previous version. When the class is registered, it keeps this number, so objects which are instances of the development class can still be used. |
Unregistered Class in Registered Range | Forcing developers to register their classes (with open source, since broken classes on the OOSys class server need the possibility to be fixed) would limit the possible use of OOSys. Therefore, proprietary classes must be part of OOSys as well. If an unregistered class is not found, the object is simply not accessible. If classes are not registered, there must be another way to prevent two classes from having the same ID. One way is to assign ID ranges to developers and let developers choose their own IDs in their ranges. |
Unregistered Class with Random ID | The second way to use unregistered classes is through pseudo-random IDs. This is the approach which software developers who do not want to register themselves anywhere should be most comfortable with. The downside is that these IDs need to be large enough to prevent classes from having the same ID. |
Internal Class | Classes which are internal to certain software (usually object editors in OOSys) and are of no use outside the software do not need to be registered. Objects of such classes may only be stored in the system RAM, storing them at permanent locations must be forbidden. |
When designing the IDs, size, speed, and scalability must be the primary goals. The IDs should be as small as possible. If a class is available on the computer, it must be accessed instantly. The possible range of registered classes may not be too small, especially since development classes may be dropped silently by their implementers. Two development classes with equal IDs may exist if they use a different magic number, but only one of them may be registered later.
The next attribute of a class is its name. Since this name is a string, it should be stored as an object. By storing all strings as objects, the maximum flexibility can be guaranteed; for example, it makes sense to store strings in a multi-language format, in a way which allows for multi-byte and single-byte characters at the same time, etc. This is a small quirk of the format: The class format itself is implemented using objects, and therefore classes. It seems that this is possible as long as the attribute is not vital (the class name is not, a class does not necessarily need a name at all).
Along with the name, there should be a description for the user. In fact, everything in OOSys should contain descriptions supporting a minimum amount of formatting as well as OOSys-internal hyperlinks (see Text Classes). This creates a help system which is as close to the topic as it can be.
Properties, which are part of the class format, can use a number of different styles. They can simply wrap around a variable stored in the object. When the property changes, code may be executed, which may optionally be overridden (actually, even if no code is executed in one class, code may be executed in a derived class). But there should also be a possibility for the property not to correspond to a variable. In this case, code must be executed to read and write the property. Properties may be read-only. Each property has a type, which is a reference to another class (or the class itself; creating a recursive data type). If a property wraps around a variable, it may encapsulate an object, meaning that the object is created and deleted along with each instance of the class. Then the reference is never empty. If this is the case, the object may be pre-initialized; that is, the values of its properties may be specified.
Methods execute code with given parameters. They may optionally return one or more results. Parameters must have a given type, which is a reference to a class. They may be constant, which means that the method may not modify the object passed to it. Parameters may be optional. They may also have a default value. Empty methods may be marked as abstract, which means that they may only be executed in a derived class.
Classes may be marked as abstract as well, which means that no object of this class may be created. A class with abstract methods does not necessarily have to be completely abstract, and an abstract class does not necessarily need to contain any abstract methods. However, a correspondence between the two meanings of "abstract" is likely.
Classes may be derived from other classes, which inherits all the properties and methods of the ancestor class. Multiple inheritance should be allowed, but there must be one main ancestor, and all other ancestors should be abstract classes. Code may be overridden; either code will be marked as overridable, or all code may be overridden. Which implementation will be chosen depends on how much calculation time overridable code takes.
One idea about how classes might be stored is to store them as objects. This makes the implementation of references to classes easier, and modifying classes becomes similar to modifying objects. When a class is used, a copy of its object is created in memory. Since these objects are very special (they don't contain a class reference), their implementation may be difficult, but it should be possible.
There need to be certain built-in classes, among which are numbers, characters, Boolean values, and enumerations. They should provide as many of the features of normal classes as possible; for example, it should be possible to derive a new class from a built-in class, adding new methods and properties, maybe even overriding existing ones.
Classes may contain other items as required by OOSys. For example, it is a good idea for classes to contain an icon, so they can be identified by the user.
When classes are transferred between two computers, the data defining the classes should carry information about the byte order of the numbers used. If the byte order on the receiving computer differs from the byte order of the class, the system should swap the bytes accordingly.
The first item every object contains is a reference to the class. When an object is referenced, it may be referenced as an object of exactly this class or any ancestor class.
An object may contain a description just like a class. It may have a name, although most objects will be unnamed. The name is only important if the object is a member of a list, and this list is displayed on the screen. If the object is stored in a file, the name should correspond to the file name. An object should also be capable of carrying an icon, to override the icon of its class.
An object needs to contain the current values of all of its properties. If the value is still at the default, it does not have to be stored, but it might be a good idea to store it anyway for efficiency reasons. If the property is an instance of a built-in class, the value can be stored in a built-in way.
As noted in Object References, each object needs to contain a list of all references, mainly to clear them when the object is deleted. If the list is empty, this means that nobody knows about the object. If it is stored on a disk, this is normal: The primary list containing the object is a "directory" in the underlying system, not the property of an OOSys object (except if one day there will be a native OOSys implementation without any underlying system). If it is stored in the system RAM, this means that it has really been forgotten, and nobody will ever know about it any more. If this is the case, it might as well be deleted. The effect is that it stays alive until it is either deleted explicitly, or all of its references are cleared.
The issue of byte order applies to objects as well. All files containing objects need to include their byte order.
Object lists are a feature which is usually missing from object-oriented programming languages, when in fact they are the last piece of the object-oriented puzzle. Usually, they are implemented inside a standard library, which limits their use. In OOSys, they are a substantial part of the object-oriented implementation.
An object list has a base class; all of the members must be members of either this class or a derived class. The members should have a specified order, but finding a given member should work very quickly, so removing members does not take long (hashing is probably a good idea). It must be possible to delete all objects in the list (that is, not simply remove them from the list, but destroy them). It should be easy to loop through the list and access the individual objects, but accessing objects by their place number does not necessarily need to be implemented.
An object can be member of more than one object list. When it is deleted, the reference list takes care of removing it from all of its lists. The reason for the fact that other implementations of object lists are incomplete is that such reference lists do not exist in current programming languages.
An object list is a type, just like a class. The reason why an object list may not simply be a class is that the base class is part of its own type. That is, when specifying a property, variable, or parameter to be an object list, the programmer also needs to specify the base class of the list.
In object-oriented programming, good programming style can be encouraged if all connections between objects are traceable in both directions. For example, if object List contains a property with a list of objects that include object Item, Item should be able to find List in some way. Usually, this will be handled by a property like Parent inside of Item, but as a special benefit to programmers, an OOSys object could simply keep a list of all object lists it is part of. Since an object needs to keep a list of all references anyway, this would not waste space or speed. There is still the question of how the system can get from the object list along the property to the containing object, but this can be solved by adding a reference of the containing object to each object list which is encapsulated, along with an ID of the property that encapsulates it.
Creating a copy of an object can be implemented in a rather simple way. Since the state of the object can be fully described through its properties, OOSys simply needs to assign all properties from one object to the other.
If each of the properties uses the same code to handle the change of the property, this code needs to be executed only once, after the last change. To detect this, they really need to have references to the same code object; the easiest solution would be to use methods without parameters.
Writing program code in OOSys is different from writing programs in a usual programming language. It cannot be written as text, since names of classes, properties, and methods are user-visible and should therefore be translatable. Instead, each line of code should be an object itself, which implicitly introduces a completely new programming "language."
Every method of a class, as well as every change handler of a property, is the root of a tree of code objects. A code object can be an assignment, a method call, a conditional branch, or a loop (which is a nice example of deriving classes from an abstract ancestor class, by the way). If it is a conditional or a loop, it recursively contains other code objects.
This way, instead of typing the names of classes and variables yourself, you select them by browsing through existing ones, creating new ones on the way. Various searching capabilities can make this seemingly long task very short, so that writing code may actually be faster than with usual programming languages.
The code is then interpreted. The interpreter should be as fast as possible while maintaining portability, so it should be written in plain C. It should work directly with code objects and classes, so no compilation is necessary. The only pass on the code may be a "release version" pass which removes the names of all internal classes and variables, as well the descriptions ("comments").
Although it is possible to write usual programs this way, it should be discouraged in the long run. In OOSys, it is much cleaner to write object editors (see Object Editors). They operate on a single object which is visible to the user. That is, when the user wants to edit an object, he/she will open it and see a list of properties and methods (this is actually an object editor as well). If this is not sufficient (for example because he/she prefers WYSIWYG word processing over defining the structure of a document only), he/she will select another available object editor for this class.
The most basic object editor will provide a list of all properties and methods. They should be sorted and classified inside the class. Object lists are handled accordingly; users are able to add and remove items and edit them in their own object editor.
The main goal of an object editor is complete transparency. If you change a property of the object in one editor, the other editors will update their visuals accordingly. This should happen automatically if object editors are programmed well, as an action inside each editor should be able to change the exact same property. For example, if you move a box inside an editor with your mouse, all the editor should do is change the properties related to the location. When you change the properties from outside (i.e. from another editor), the exact same thing will happen.
To accomplish this, every property must have a list of change handlers at run time, and the object editors simply attach themselves to this list. This is similar to the code that is defined for the property inside the class.
There should also be object editors for classes and code objects. This means that extending OOSys can be done comfortably inside OOSys itself. Furthermore, it provides a good way to implement a "macro language" without reinventing the wheel.
Like most other programming languages, the OOSys language needs a standard library, which implements many features which are too specific to implement in the language itself, but too general to be left to other programmers' choices. The number of standard classes needed by OOSys is rather small, as many features are already implemented in the language. For example, object lists are usually part of the standard library of an object-oriented language.
Text classes are of special interest because they are needed very often. Therefore they need a good and flexible implementation. In general, a text is simply a list of characters, but implementing text classes this way would be too inefficient. However, there should probably not be a built-in text class, as characters should be organized in normal object lists (see Object Lists).
Additionally to a list of characters, text should also be accessible via a list of lines, each containing a list of characters. Such a situation (an object needs to contain several lists to describe the same data) is actually not uncommon. If this is the case, some of the lists should be virtual, which means that the actual objects are created by program code. This is similar to getting the value of a normal property using code, and should be done in the same way.
In text classes, both lists should be virtual for efficiency, and the actual text should be handled through binary data. This also means that there must be a class related to binary data, which must be built-in, since no real class may operate on raw binary data. There should be an option whether text is to be stored line by line or as one complete string.
Even though the character objects are created on demand, they may still be referenced, and stay in memory as long as they are referenced. If text is inserted or deleted in front of the character, the reference must stay valid. Programmers will be very comfortable with this. There should be a special "end of string" character which allows a programmer to reference the position after the last character.
Text should either be stored in a multi-byte format unconditionally, or the format should be selectable via a property, whichever is more efficient. Another property should specify which characters are used to mark the end of the line.
There should be the possibility to store text in multiple languages in a single text object. When using the text (displaying, querying the length, etc.), the preferred language of all of the available languages should be used.
A special extended text class is important in OOSys: For the documentation of the different OOSys classes and objects, it should be possible to insert references to other classes and objects directly into the text. This can be achieved by inserting the name of the class or object in the current language into the actual text, and referencing the first and last character of it.
Layouting components ("frames") in a pixel-based system is a task which is shared among many applications. When designing object editors and dialog windows, as well as when doing word processing or creating a presentation or hypertext document, programmers and users perform this task of layouting. By providing classes related to layouting, OOSys can unify the way layouting is done, and make layouting more stable.
Components should always be aligned to each other, as well as to the boundaries of the system they reside in. Properties should be used to define sizes, spacing, padding, and everything which cannot be described using such an alignment system. Components should not be able to float around unaligned; if they need to be placed at specific pixels, they must be aligned to the upper and left side of the system, with appropriate spacing.
For word processing, this restriction is not as important (although it can actually be very useful) as it is for window design. Currently, window design usually deals with exact pixel numbers, creating problems when the font size is to be changed (usually along with the screen resolution). If components are aligned to each other, these problems should not occur.
There are certain requirements for this to work. For example, it must be possible to auto-calculate the width and/or height of some components based on the text they contain. For other components, this is only a minimum width or height, and they are resizable beyond that. The resizability of a window or group of components should be based on the resizability of the individual components; if more than one is resizable, the sizes should be distributed equally or in relation to the minimum size.
The properties that control sizes should have units attached to them. These units must include real-world units, so that the same layout formats can be used for window design, word processing, and similar tasks. There should also be some special units corresponding to the width and height of the component itself, the height of one line of text, and maybe more. This would provide users and programmers with the maximum possible flexibility in choosing their design.
Since layout classes should be written with maximum speed in mind, a good idea would be to implement them in a compiled language. This requires an easy way to interface with code written in other languages, but this is necessary anyway to support the API of the underlying operating system.
Layout classes for user tasks such as word processing should be separate from the standard OOSys layout class. They must extend the capabilities of the standard class to support word processing concepts like text wrapping around a frame or picture, page breaks, and footnotes. However, as soon as an OOSys layout class is implemented, such classes related to other tasks will follow quickly.
Many different file formats already exist; files must be read and written as raw binary data with a specific format. To provide maximum comfort for the user, OOSys should support as many existing file formats as possible.
It can do this through special classes, each of which is related to exactly one file format. An object of such a class must be able to fill itself using raw data as input. It must also be able to write its contents to raw data. The data should be accessed as a stream (such streams may either be objects or built into OOSys), so that incremental reading of the data is possible (for example when retrieving the file over a network, or when reading a large picture).
One thing which would be a nice addition but is not required is to allow in-place editing for such objects as well. This would only be possible with file formats which either have a fixed size (for example, uncompressed pictures with a specific size) or have their own memory allocation system (for example, certain database formats).
A lot of formats are already object-oriented to some extent. HTML, the most popular hypertext format available, uses cascaded tags to format its text. In an object-oriented structure, a pair of tags would become an object containing a list of sub-objects (either text or even more tags). Document formats are usually object-oriented because the applications that use them are so complicated that they simply have to use object-oriented approaches. Other formats are not object-oriented but can benefit from an object-oriented view. For example, editing a MIDI file in OOSys through the appropriate file class will be much easier than editing it with a hex editor.
Usually the only object editor available for such a class will be the default one, which allows the user to view the object's properties and execute its methods. However, this is already more than an average user of a current operating system can get out of the file. Using such an editor is not only easier than writing a program to manage the format or hex-editing a file, but users can also be sure that the structure of the object will be kept intact. This is an important concept of object-oriented programming: There cannot be any violation of a data format; every action a user can take is safe.
Even if no appropriate editor for the class is available, it may still be possible to convert the object to another class (see Object Converters). For example, object converters should exist for all supported text documents (including hypertext) to a layout class specific to OOSys. Once such a converter is written, the object can be viewed and edited without needing the application it was originally written for.
When writing file classes, programmers should make use of structures which act as templates on the raw binary data. These structures could be imported from C language structures, for example. Program code can be used to specify which structure to use at which position. Reading files can then be implemented in two stages: In the first stage, the structures and their positions in the data are defined. After that, you should already be able to look at the file through these structures. In the second stage, the structures are read and written to properties.
An object converter can convert any object of one specific class into an object of another specific class. Both objects can use classes derived from the classes specified in the converter.
When dealing with object conversion, users should be presented with a list of possible target classes (for example in a menu or list box). Even classes for which several conversions are necessary should be listed; in this case, the conversion with the least number of steps should be used. This way, it will be possible to convert an HTML file to a Latex document with a single click, for example, even though the conversion is rather complicated. If a programmer wants to specify explicitly which steps to take for a conversion consisting of multiple steps, he/she can define a single-step conversion which simply uses the other converters.
Object converters will not only exist for file classes, but also for some general OOSys classes. For example, an object converter could be implemented to convert a layout object to a text object, stripping all of the formatting. Or, if a Computer Algebra System (CAS) is implemented in OOSys, a converter could change a user-designed formula to a CAS formula. Object converters can also be used to perform simple tasks like string to number and number to string conversion.
There should be the possibility of creating incremental object converters. This means that a converter stays active for some time, and every addition to the original object is transferred to the converted object immediately. For example, if an HTML file is received in pieces, the corresponding file class will start building an object when the first piece is received (see File Classes). When more pieces are received, the object will grow. The converter to a layout class (see Layout Classes), which should be incremental, can be started at any time, and it will update the layout object as long as the connection is active.
If objects can be stored in files with a memory allocation system, they are accessible quickly, the files' integrity is always satisfied even if the system crashes while writing a file, and the objects can reference each other in a number of different ways, then such objects can be used to create a database. Since all of these conditions have to be met in OOSys anyway, OOSys seems like an ideal testing ground for object-oriented databases.
The databases which can be implemented natively in OOSys are not relational. Instead, databases are built using object trees, i.e. cascading objects. The structure of these trees is defined by classes created by the database developer; sub-objects are maintained using object lists. Every object can reference every other object, either directly using a single property or through object lists.
However, database objects need a few extensions over other objects, which should always be present if they do not take any additional space or speed, or be activated by the database developer. These include:
Indexing: Every property of a class must have the ability to be indexed for faster searching (in every object list which contains objects of this class).
Searching: Every object list must have the ability to search for the value of a given property in each of its items. Advanced searching should be possible, using an equivalent to regular expressions. A search should return the first object which meets a condition, and should be continuable. The return type is equal to the type of object searched for. Searching through sub-objects should be possible, returning (at the user's request) either the parent object or the sub-object.
Selecting: Object lists should be able to generate another object list with all items meeting a specific condition.
Counting: Object lists should be able to count all items which meet a specific condition.
Calculating: Object lists should have the ability to quickly do calculations on properties of their items.
Merging: For queries merging two or more object lists ("tables"), there should be the possibility of quickly merging the properties of two or more different objects into a new object of another class (specific to the query).
Remote Controlling: For large databases, remote controlling is essential. Program code must be created and executed on the database server, using either a protected variant of the OOSys language or a database-specific language.
The user interface of the OOSys system should be rather simple. It should mainly consist of a tree of objects, which can be viewed, edited, copied, moved, etc. Typical features of the underlying operating system, for example drag&drop and context menus, should be supported.
When viewing or editing an object, users should be able to select an appropriate object viewer or editor (an object viewer works just like a read-only object editor, see Object Editors). Converting objects should be possible with a single click (see Object Converters). A list of object viewers and editors (which can be included in the context menu) should contain viewers and editors for classes which the object can be converted to as well; the conversion should be done automatically. Conversion should always create a copy of the object; it should never overwrite the original object.
When editing an object, the medium the object is stored in along with its type (see Object Storage) should be visible to the user. Users should be able to create a temporary copy of the same object in the computer's RAM, and write its contents back to the original object.
Object editors should be able to live either in a floating window or in a portion of the main window. Several object editors should be able to live in a single window. The menu of the window should correspond to the currently active object editor.
The main user interface should contain two tab sheets, one which contains the objects stored on the hard disk or internal to OOSys, and one which contains the classes OOSys knows about. Users should be able to download classes or only information about them, including available converters from and to the class, available object editors for the class, and a description of the class. When classes are edited, it is probably best to switch to the object tab, since classes are treated as objects in this case.
Context help including hyperlinks to objects and classes should be available for every item in OOSys using its description. This requires a special text class (see Text Classes).
Since in OOSys, error messages are likely to contain hyperlinks to objects and classes, they should not be displayed in dialog boxes, as this would block the entire OOSys system and not allow access to the linked items. Instead, they should probably be in displayed in a portion of the main window or in a floating window, as it is usual in compilers. This includes warning messages and most types of errors.
Users should be able to jump to the relevant object by clicking the message, and dismiss all or some messages. Every message should reference the object which is closest to the position of the error.
Errors may occur in program code, when a device is not ready, when a file class encounters an error in the file format, or when an object converter encounters a situation where conversion is not possible.
There should be certain types of objects that correspond to items on the screen. They should have a common ancestor class which can be used by a layout class (see Layout Classes); this class should define basic properties like position and size, but it should not be used directly. Instead, the layout object aligns the visual objects in their window.
Many visual objects actually correspond to other objects. An edit box will most likely correspond to a text object, while a list with columns will likely correspond to an object list, the columns representing properties of the contained objects. This should be taken care of automatically by linking to the represented objects in the visual object's properties. Since properties can be references to other objects of some specific type, this is possible. In a visual list in which each item represents an object in an object list, programmers first have to define a visual list item class corresponding to the class of the object. This class defines the columns of the list.
The usual way to deal with interactive elements such as buttons is to define "events" as properties that take a reference to a method with specific parameters. This way is suboptimal because once an event is filled, no code can be added to it, which becomes a problem when deriving classes for visual objects from other classes. Instead, creating interactivity is actually related to deriving classes, since the object behaves differently from another object of the same class. So, to achieve interactivity, users should be forced to derive a new class from the existing visual class, overriding certain methods which are executed on user input.
Since all classes should be reusable on their own, this new class cannot access other elements in the window directly because it does not know about the other visual objects inside its parent window. Instead, it should have properties for the exact objects it needs to operate on, and these properties' default values should be filled automatically when designing the window. If the class is reused, the properties need to be filled manually, or the objects which are referenced inside them must be reused as well.
When designing dialog windows, the visual objects inside the window often correspond to properties of the same object. So creating dialogs can be simplified by providing a list of properties for a given object, and suggesting classes of visual objects for each property.
Dialog windows will often work on a copy of the actual object. This copy can be discarded or assigned back to the original object. However, working on the actual object should be permitted as well, for example if the effects of changes should be visible immediately. As an intermediate solution, users can be allowed to assign the object back to the original one at any time using a button.
Since objects containing other objects are best described in a tree, OOSys will need a visual tree widget with special capabilities. These capabilities include multiple columns, the possibility of multiple selection, and maybe basic formatting capabilities for the text of each item.
If different people work on the same piece of program code, they need a way to merge their results, track all changes, summarize them, and find duplicate changes.
Usually, these tasks are managed by programs that compare two versions of the same source code in text form and apply source code patches with context information to different versions of the same file. However, since OOSys program code is not edited in text form, OOSys needs another way to manage the same tasks. (Actually, every object in OOSys can be exported to plain text and imported from plain text quite easily as an extension to OOSys, but this is a suboptimal way of handling the situation. It should be implemented regardless.)
To be able to refer to code objects in different versions of the same class, every code object needs an ID attached to it (probably a combination of random and incremental elements). This ID can be removed in the release version. When code objects are referred to in a network, their IDs should be used.
Every change in a class should be recorded; including the ID of the code object which was changed, the state before and after, the position in case of addition or deletion, and the ID of the parent object in case of addition. This not only provides useful undo information, but also the ability to view and undo specific past changes.
Programmers should get the ability to organize their changes in tasks, by specifying a "current task" and being able to move changes from one task to another. There should be open and closed tasks; tasks should be able to include sub-tasks. Just like every line of code, programmers should be able to attach comments to changes and tasks.
Changes and tasks should not be encapsulated in the program code objects. Instead, there should be the possibility to pass them around on their own. When passing a task on to someone else (for example to include the changes in the upstream version of the code), all the changes it contains should be passed on as well.
When applying all changes in a completed task which was sent by someone else, OOSys should record when the task was applied, and summarize the changes made. Changes to code which has already been modified should generate warnings, allowing for user interaction (see Error Reporting). Duplicate changes should be detected automatically and produce warnings as well. Information about this should be collected in the task, with links to the other related tasks.
OOSys could provide a lot of benefits to both users and programmers. Benefits to users include:
By describing all elements of software with one single concept, users only need to learn how to deal with this single concept; after that, they can quickly adapt to new elements.
Users can see immediately how their operations affect the objects they work on. This prevents unwanted actions and reduces the frustration that many users encounter when working with computers.
Instead of using large programs to perform a large number of tasks, OOSys users can make direct use of small classes and object editors to perform only the tasks they need.
OOSys can provide cross-platform compatibility, which then includes all of its classes. Since there are no special file formats related to single programs, OOSys can help prevent monopolistic practices of some companies, resulting in faster innovation.
Users always have full access to all of the features that are implemented in OOSys, since classes which are usually used by other classes can be used on their own. Presently, if someone has a nonstandard device which is connected to the computer, this device can usually only be accessed through one program. If access to the device was implemented using OOSys classes, users could not only access it directly using these classes, but also write code (including macros) to control it.
If life is made easier for programmers, users can benefit from fewer bugs and faster development.
Benefits to programmers include:
Code does not need to be compiled. This can greatly reduce the time needed to write it.
It is not possible to make syntactical mistakes when writing code, since program code is not described as text.
There are no restrictions on the names of classes, variables, etc. In typical programming languages, spaces and special characters are not allowed.
All strings, including names, can be translated into other languages.
Programmers can reuse existing code more easily. All classes written in OOSys can be reused by all programmers.
In programming languages, usually there are many possible styles with respect to indentation, bracing, spaces, etc. Code written by different programmers is often a mixture of different styles. In OOSys, there are no such styles; the stylistic devices of program code can be selected when viewing it.
OOSys also reduces the gap between users and programmers, since both will access the same elements from similar perspectives. This makes communication easier, and it enables more people to program.
Every system has certain restrictions, and so does OOSys:
Speed-critical systems cannot be ported to OOSys, as code written in the OOSys language is interpreted and therefore slower than usual compiled code. However, OOSys classes can be used to access speed-critical systems written in other languages.
OOSys does not fulfill the special needs of many industries. Industry-specific programs are not likely to be ported to OOSys, and existing databases are usually left untouched because they already work as expected. New people are simply taught the concepts of the programs and databases, and they usually only need to deal with a small portion of the systems they work on.
Since program code is interpreted and not compiled and optimized, even release versions of classes are readable to some extent. Although variable names and the names of elements of internal classes are removed, the structure of the code may be viewed directly in an object editor.
Since there are certain factors in the underlying operating system which are out of OOSys' control, OOSys will never be able to guarantee security and stability. If it is implemented as free software, there will not be any possible warranty either. However, the interpreter is likely to be very stable, and security can be provided for by the underlying system.
Interoperability with existing software is restricted by the constraints of that software. If the standards used by the software are closed to the public, interoperability is close to impossible. Interoperability may also be an issue of time: Many existing standards are so complicated that proper interoperability will take a lot of time.
Unlike certain systems, OOSys cannot be remote-controlled through simple commands.
There are certain types of applications, or tasks, which are more likely to become integrated into OOSys than others. This does not mean that integration of other applications is impossible. Almost all tasks which are not speed-critical may be performed by program code written in the OOSys language.
Typical applications include:
In general, all applications in which object-oriented principles are likely to be of some use can be done well in OOSys.
To implement OOSys, it is necessary to build several components at first, since other components rely on them. Unlike small-scale applications, it is not possible to simply start coding something.
The first thing needed in OOSys is the ability to write program code (see Program Code). Once program code can be written in the actual OOSys language, all code which is written without the final goal in mind can be reused quite easily. However, most efforts done with code written in another language are actually wasted time.
To write code, the first tool needed is an IDE. It should be written in some easy to read, not necessarily portable language. Although it does not have to use OOSys objects internally, it should be able to store all program code in the exact format which will be used later by OOSys. It should also implement basic ideas like registered and unregistered classes (see Class Format).
To actually be able to use code written in this IDE, the interpreter for the code needs to be written. This is already the core part of OOSys. Care should be taken to write this interpreter in a way that allows for many different styles of invocation. There should be the possibility to execute code directly from the IDE, to run an OOSys program from an interpreter installed in the system, and to create a single executable file carrying both the interpreter and the program.
Since this IDE is not meant to be used for a very long time, not a lot of effort should go into it. In particular, it is not necessary to be able to design the visual interfaces of applications inside this IDE. Support for OOSys layout classes would be needed to implement this, and such support would be hard to write because the IDE is not written in the OOSys language yet.
Indeed, writing the standard text and layout classes is the next thing to do. Once these are finished, applications written in the IDE can use them, although WYSIWYG-style window design is not possible yet. Next, a basic set of standard visual components needs to be implemented on top of a single operating system. It needs to support at least the types of components which are used by the IDE itself, so that the IDE can be rewritten in the OOSys language.
Next, the IDE should finally be rewritten. It should be implemented as an object editor, which is a new concept in OOSys (see Object Editors). However, it will look just like the old IDE, since there will be a wrapper program around this object editor. One new thing about it is that drag and drop editing of components in windows can be implemented easily through the existing OOSys layout classes. Another new feature, which will not be visible, is that code which is executed directly from the IDE will actually be run through the interpreter used by the IDE itself.
With an IDE written in its own language, at this time OOSys will have proven that it, or at least its language, is efficient and well-designed enough for application design. Adding new features to the IDE will become easy, and maybe some developers will be attracted by this new language. Now it is important to implement the actual OOSys system.
Implementing OOSys should not be too hard. Since the interpreter already works, the focus can be on the user interface. Probably class downloads and several localization issues have to be addressed as well. The basic object editor for all classes should be implemented as soon as possible, as it is one of the core features of OOSys. Porting OOSys to several platforms can increase the number of users.
While there should be several example file classes to show their concept so that other people can implement more of them, the primary focus should then be on the user-visible layout classes. Currently there are very few usable word processors available; if the OOSys developers manage to create a stable, flexible, and light-weight implementation of word processing, OOSys could get an instant user community. The same is true for a light-weight and fast web browser.
At this point (if OOSys ever gets this far), there will be a great variety of possibilities, and OOSys will be able to compete with established systems. Maybe some time in the future, OOSys will be able to run on bare hardware instead of on top of another operating system. At least it should be possible to port OOSys to terminal-based systems, to be accessed from networked computers. Then OOSys would actually get the same powers as Unix systems.
Interestingly, this outline specifies not only the stages in which OOSys should be implemented, but it is also a description of my own line of thought. At first, I actually thought of a programming language. As the possible features of such a programming language evolved (for example to support object persistence), the idea of a complete object-oriented operating system came to my mind. If you take a closer look, you will see that the power of the system grows with each new stage of development, i.e. with each new idea. It is good to know that such a system does not need a jump start, and if it is ever abandoned at any time, all the pieces that are already there stay usable and remain useful.
In fact, even if this list looks very large, I am confident that the OOSys language will be very useful even after the first temporary implementation of an IDE. And the actual system will be useful as soon as it is implemented on a single platform. If something can be used to some extent, all the work spent on it will never become worthless.
March 19, 2003: Version 1.02
Changed "static" to "procedure-oriented" in the introduction.
Fixed a typo: "object handler" instead of "object editor".
December 30, 2002: Version 1.01
Fixed a broken link in the introduction.
December 29, 2002: Version 1.0