What is this all about?
Technical answer: Om is a suite of conventions and software libraries that implement those conventions. The highest-level library for each language is also called Om (libom for C, pyom for python, voom for V, etc), because this library is meant to encapsulate the whole suite in one set of semantics; but it's possible to use only a subset of the lower-level libraries if you want (or even none of them but some of the conventions), and still call your project “Om-compatible”.
Rationale answer: Om is an attempt to bring the higher-level aspects of software development up to the same geological age as our languages and tools have already been for years.
What's wrong with the way things are? (Or: the Om Manifesto)
Most software development these days is object-oriented to some extent. However, the object model stops in the application boundaries; we're still, in the end, developing applications, which run monolithically, based on a model not too different to what UNIX had in the 70s and DOS had in the 80s.
Instead, I want to write classes, interfaces, adapters, and have everything in my system potentially interact with anything else.
Almost every software project has to, very early on its lifecycle, decide on data storage. Usually there's some sort of library that does what the project needs. Usually, it has a non-trivial learning curve, and does a lot of magic to hammer your object-oriented data into relational database tables.
Instead, I want to just write my “business logic” code, then pick storage options from an off-the-shelf selection. It's a solved problem, why must every project go through it again?
The majority of applications today is tightly bound to its user interface. You close the window, it stops running. There's no way to “reattach” to the running application from, for example, a different computer. At the same time, a lot of state is lost when the application is closed.
Instead, I'd like to log out of my GUI session, and keep receiving updates from IRC, IM, and microblogging; I'd like my downloads to keep going, my music to keep playing, etc. I'd like to be able to open multiple different views on the same object, even simultaneously, to fulfill different UI needs. I'd like to be able to attach to my objects from a different computer. Finally, most of my state doesn't really need a process to be running; the system should be able to persist most of it even when nothing interesting is happening to my objects, so I can pick up from exactly where I left.
If a project requires client-server communication, it almost always will design its own protocol. The developers will spend a lot of effort improving, fine-tuning, optimizing, and securing this protocol, but at the bottom line it's really a simple, crippled message-passing system (assuming the project is object-oriented).
Instead, I dream of writing my “business logic” code, then just flip a switch to tell it I want the network message passing system enabled. Possibly register which objects are visible and “where”.
On the other hand, a lot of “client-server” has been replaced lately with web-based applications. Having been a web developer myself, for over a decade, I'm hardly a fan of the model. HTML was designed for documents, not for modern user interfaces; HTTP is stateless and sessionless, fundamentally pull-only (so-called “server push” is an ugly hack which does something not quite exactly what it advertises). Although our desktops have evolved to a wide host of modern programming languages and tools, there is in effect only one language that web applications can use in the client side, and this language suffers from nightmarish differences in implementation across browsers. Finally, web applications are still seen as “sites”, and therefore a lot of effort is wasted in making them pretty, sacrificing consistency, native looks, user preference, and quite often, good taste. Portability (for example, to mobile devices) usually means reimplementing the UI from scratch.
Instead, I would prefer to see my multi-user client-server applications using object-oriented semantics, a consistent, cohesive, hack-free model, a stateful and session-based protocol, and the flexible, portable user interface semantics already mentioned above. Portability would be automatic; once there is an UI “viewer” for a given platform, it can display any application, with native, consistent appearance and accessible semantics, and respecting user UI preferences.
More than 20 years ago, UNIX and its library model freed us from the language-lock; we can now easily make full use of system resources regardless of what language we choose to program in, and even implement different parts of our program in different languages. However, this freedom is mostly at the library layer only, making it relatively difficult to enjoy it. Furthermore, it helps a lot less with dynamic (or “interpreted”) languages. In practice, a modern project still has to pick a language and stick with it, with a few rare exceptions (where it picks two).
Instead, I see no reason why a central object model couldn't connect assorted pieces of code, regardless of language.
With the insistence in the “application” model, we got to a point where every piece of software interesting enough that you'd want to modify, is exceedingly complex and hard to understand. Want to fix a bug in Firefox or OpenOffice.org? Please, by all means, but you should set aside at least one week to understand the existing code and how things work.
Instead, I want a world of small, discrete components that talk to each other, each one relatively easy to understand and modify. That would also mean it's easy to modify them; you can change only the part you want to change, and you don't have to rebuild and restart a whole, enormous package in order to test your changes and discover you forgot a comma.
The object model
So what does this object model look like?
The fundamental object model is divided in three levels of compliance. This allows non-Om applications to communicate with Om objects, by using only specific lower-level libraries, or implementing specific subsystems their own way. Each subsystem and library requires or supplies a minimal compliance level.
Compliance level 1
At this level, Om deals with two separate kinds of entity: objects, and atoms. Objects are fully opaque, supporting only one operation (messages). Atoms are simpler things, like integers or strings, but one possible kind of atom is a reference to an object.
Objects support a number of messages. Each message takes only three pieces of information: a selector (usually a string, but any atom may be a selector), a recipient (a reference to an object), and a sender (also a reference, although optional). Messages may fail for a number of reasons (object doesn't support that message, lack of authorization, etc.); if they succeed, they result in a new Om process. A process may run quickly, or over some time. It has some associated state: whether it's currently running, not yet started, or finished, and whether it has an exception condition.
While a process is running, data can be passed in and out of it, as a pack of atoms. Some process may do this only once, others may allow multiple “data packs” in and out.
Compliance level 2
Every object has exactly one interface. The interface is a symbol (textual value) and can be retrieved via introspection.
A host has a registry of interface synonyms. You can ask for the “canonical“ name of an interface, or compare two and ask if they're synonyms.
Atomic values can be treated as objects.
A message with the null selector (“nothing”) is interpreted as executing the object proper; an object that can be executed this way is called a “callable” object, and an interface that requires that is a “callable” interface.
Every object has exactly one facade. The facade is a symbol and can be retrieved via introspection. It represents the concrete implementation of an interface (or in other words, a bunch of code which implements the messages).
You can request for any object to be cast to any interface. If the object supports that interface (if there is an available facade) or if the host has some other way of adapting it, the cast will result in a new object, with the requested interface, but still representing the same underlying data. (A cast may also fail for other reasons, such as authorization.)
Compliance level 3
This level adds one special interface, the null interface (“nothing” for the interface name). It contains only methods that get and set attributes on the raw object, and introspect its schema (list the attributes and their types, if any).
Interfaces correspond to interface objects which can be retrieved and used as normal objects. The Interface interface has methods that provide information on the messages required by the interface, type information on the messages if any, whether each message is “quick” (no multi-messaging), inheritance relationships between interfaces, plus DublinCore metadata.
Facades correspond to facade objects, which have callables corresponding to the implemented messages.
With these interfaces, it's possible to modify interfaces and facades, or build them from scratch, via reflection. (Although it may be disabled, which would be seen as either the necessary interfaces/facades not being available, or no authorization.)
Services
An Om host includes exactly one “service manager”. The service manager is exposed as an Om object on compliance level 3, but may be available via native API on any level. It keeps track of a number of “services”, which can be registered and retrieved by interface; there can be only one service registered for a given interface at any time.
There is no further requirement on services except for implementing their own specific interface, but they're encouraged to be cast-able to the DublinCore interface.
Services are used to tie in to some subsystems, such as OOPS and COOLEST.
Subsystems
These subsystems are implemented by separate libraries, some of which may be usable independently.
OOMPH: The network protocol
OOMPH fulfills one of the main Om motivations, by providing a simple object-oriented remote call (or “message-passing”, in classic OOP parlance) protocol. It's designed to be useful even for non-Om code, so that existing/legacy applications can become “Om-compatible” by communicating with Om objects via OOMPH, or even as an efficient, off-the-shelf object-oriented message-passing network protocol for applications not in any way related to Om.
| Compliance: | OOMPH requires and enforces compliance level 1. Transient objects (TOBJs) and exception detail reporting assume compliance level 2 (although it's possible to use them with level 1 and a different set of higher-level semantics). TOBJs transport the interface and facade as the special attributes “.interface” and “.facade”. |
|---|
OOPS: The persistence system
OOPS implements another basic goal: a transparent persistence system. Objects held on OOPS don't need to be saved or loaded, they're just “there”.
| Compliance: | OOPS requires compliance level 3. |
|---|
COOLEST: Loadable extensions
COOLEST provides a simple to use, flexible way to dynamically load code at run time. It provides loadable compiled modules (“plug-ins” roughly), but also “scripts” in a number of dynamic languages. The bridging between languages is all handled by COOLEST, coercing everything to Om object semantics.
Optionally, COOLEST can also integrate with OOPS, allowing code to be orthogonally persisted in an OOPS storage.
| Compliance: | COOLEST requires compliance level 3. |
|---|
OOUIOOUI: MVC reloaded
The “MVC” pattern of development has been a boon to software developers for years; it allows the developer to code models (“business logic”) without concerns about user interface, and write user interfaces that are relatively resistant to model changes.
Om's user interface package, OOUIOOUI, takes this one step further, by separating user interface logic from the actual, run-time implementation of (typically) concrete widgets on a screen. You may have more than one view open on the same object simultaneously; maybe a classic GUI view on your desktop and a mobile GUI on your phone. You can detach one view and reattach it later, or “move” (really rebuild) it to a different computer seamlessly.
| Compliance: | OOUIOOUI requires compliance level 2. |
|---|
Om: Putting it all together
Om development (full compliance — again, you can write non-Om applications that are Om-compatible or use some Om subsystems) is concerned with a few concepts, different than those usual as of this writing. Most of the development is (or should be) on implementation of facades, which provide concrete implementation to Om interfaces (most of which you will probably define as part of your project).
The second important concept is of hosts. A host is an “universe” as far as Om is concerned; a set of objects, the relationships between them, the rules governing operation, the set of available interfaces and facades, and so on.
There are two possible models of Om development:
Isolated (Om application)
In this case, you'll be developing a special-purpose host. If it needs to communicate with other components in the system, it will connect to another host by local OOMPH.
To develop a host, you can use C (or a C-compatible language) and libom, producing a “normal” executable binary; or pyom, which in practice turns a python interpreter/runtime into an Om host; or the voom stand-alone interpreter; or other similar solutions. You can choose which low-level libraries to link in, fine-tuning the features/subsystem that will be available to your application.
Full-on Om
Here you don't develop an application (remember, one of our goals is to transcend the application metaphor) or produce an executable. A project is a set of objects, mainly interfaces and facades, which can be loaded in a host via COOLEST and/or OOPS. Typically, in such an environment, each user in a computer will have one “global”, persistent, more or less daemonic host, with (in non-object-oriented OSes) one central process serving as the host's dispatch system.