Life With Objects

This is a wordy response to Chris Turner’s Life Without Objects.

Many object models compose poorly. There are no generic methods to combine two objects into a meaningful third. Rather than composition, we get a Cartesian product of specializations (e.g. BufferedInputStream, ByteArrayOutputStream). Functional programming, by comparison, focuses very heavily on composition. We model programs with composable abstractions – lenses, functors, categories, arrows, stream processors, iteratees, pipes, monad transformers.

Functional programmers often reason in terms of compositional properties – i.e. properties that are inductive across all relevant composition operators (e.g. “if A doesn’t deadlock, and B doesn’t deadlock, then A*B doesn’t deadlock”). Purity includes a nice set of compositional properties, and is most publicly associated with functional programming. But there is much interesting ground between `pure functions` and `imperative IO`. Functional programmers often seek and learn new compositional abstractions to achieve desired compositional properties and expressiveness.

It’s often difficult to achieve both expressiveness and rich composition, but invention is the art of avoiding tradeoffs!

While the functional programming community typically achieves composition by providing uniformly-structured entries and exits for every action, this isn’t strictly necessary.

The OO community pursues another viable path to expressive composition: mixins, dependency injection, and auto-wiring mechanisms in general. Ambient oriented and concept oriented programming both provide alternative approaches to resource discovery and wiring objects together. Sean McDirmid has pursued a few interesting possibilities for composition of first class objects. I’ve also been idly pursuing such mechanisms, though without the OO angle – e.g. constraint-based linkers and configuration and dependency injection for functional values.

I’d love to see mixins taken further than Scala takes them – i.e. objects as first class adjectives and adverbs, composition by juxtaposition (so we can say `green triangle`) with good defaults, typing in terms of grammatical subclasses (so we can reject constructs like `colorless green ideas sleeping furiously`). Today objects are mostly nouns (data, passive elements) and verbs (runnables, actors, agents). I think we could take auto-wiring a lot further than we do. Some ideas from Inform 7‘s object model might be applicable.

With respect to compositional properties, one excellent result from the OO community has been the object capability model, which essentially is fine-grained object-based modularity taken to its logical extreme. Ocaps are a very promising basis for secure composition and secure interaction design in open systems. Object capability model includes a valuable set of compositional properties for reasoning about effects, authority, and both hard and soft security (where “soft” security means limiting the damage caused by buggy or malicious code, enabling auditing and revocation if abuse is detected).

Fortunately, capability security is not in conflict with mixins or dependency injection. It only takes a little extra explicit modeling and formalization to avoid ambient authority, e.g. in terms of a powerbox or factory.

As OO’s composition languages become more expressive and accessible, and its compositional properties more powerful, life with objects becomes more tolerable.

(OTOH, it seems less recognizable as “OO” if you compare to prototypical examples like Java. But it’s the programming experience that matters, not fuzzy and amorphous definition of OO!)

Objects, but Stateless…

I think that even if objects prosper in some form or another, they will gradually move to be ever less stateful, and eventually `stateless objects` will be the agreed upon best practice for OO.

Mutable state will be pushed to the very edges of the model and even over the edge – into `external` database abstractions and content-centric networks. Doing so affords us many benefits – orthogonal persistence, orthogonal replication and disruption tolerance (of both the program and the data), orthogonal rewind and replay and support for backtracking debuggers (assuming we favor temporal data), runtime upgrade and live programming, reactive programming, easier administration, reduced bottlenecks and improved scalability (since we aren’t serializing messages at objects).

I’m sure people will try clever, `safe` uses of state – e.g. futures, promises, single-assignment, transactions – but they’ll discover various issues even with those, that it is better to model even promises in external state outside of any object.

We’ll have stateless, reactive objects influencing and observing a stateful grid. They won’t be pure objects, but there won’t be any local state. And good riddance.

Without internal state, object identity becomes irrelevant. Stateless objects may still be unforgeable or opaque closures that encapsulate capabilities, but it is easy to represent unforgeable (and deterministic, reproducible) identifiers for pure objects – via encryption, HMAC, secure hashes, etc.. IIRC, Waterken uses such techniques.

I think we’ll also drift a bit closer to `pure` at the services scale by shifting the data management responsibility.

Ultimately, the favored discipline will be for clients of an object or service to provide references to their own external state services, i.e. client-side state where “client side” might actually refer to some logical amalgamation of client-owned space in a cloud and the local device. There are a lot of reasons for this – it makes third party services cheaper to provide, easier to administer, and more extensible and composable (annotations on state, mashable services); it decouples the client from the service, reduces lock-in, allows clients to change component services without disrupting their state (though there may be a conversion effort), reduces legal and security concerns for hosting, etc.. We can see some beginnings of this movement @unhosted.

Services will still keep their own databases for any cross-cutting state to improve service for all clients. But they’ll mainly compete by providing unique capabilities, difficult functions, and rich features.

My Future with Objects

It would take a broad, fuzzy definition of OO to call RDP an OO paradigm. But RDP does support object capability model patterns. And I do pursue some of the auto-wiring mechanisms suitable for object composition (in addition to rich, arrow-based functional composition). RDP realizes most of my vision of what OO programming will eventually become – a clean, declarative, open, composable, internally stateless fusion of object capabilities and reactive programming. RDP’s continuous time semantics require some interesting models for external state, but state is still an essential part of many applications and the RDP experience.

My RDP is embed with objects. ^_^

This entry was posted in Language Design, Modularity, Open Systems Programming, Reactive Demand Programming. Bookmark the permalink.

5 Responses to Life With Objects

  1. Chris Turner says:

    Thanks for that fascinating follow-up to my blog post. You’ve explained a potential future direction far more eloquently than I could ever hope to achieve. There’s a great deal in your post for me to research and contemplate. However, I am persuaded of a possible future for objects in the way you describe. I think languages like Scala are just starting down this path and I’m looking forward to the fruition of some of the research concepts that you explain.

    Thanks.

  2. Steven Sagaert says:

    What you describe as “stateless, reactive objects influencing and observing a stateful grid” makes me think of Erlang. Of course Erlang is a functional programming language but is actors system & passing of immutable message could be considered as “stateless (distributed & parallel) OO”. Erlang modules could be considered as stateless classes. Note that OO is here more like OO in the sense of Smalltalk/Alan Kay than Simula and its descendants C++/Java/C#/…

    So this system actually DOES exist already. It’s just not known by the mainstream.

    • dmbarbour says:

      Erlang processes are tail-recursive loops that may accumulate state across messages: just add arguments to the loop function, or change functions. Actors model is very stateful – actors set their behavior for future messages by use of a “become” verb, and this is used extensively in design patterns for actors systems. (I would posit we’d need a much more consistent timing model than actors to support stateless objects in practice. A significant fraction of actors state is focused on regaining the consistency that Hewitt so blithely threw away at design time.) With Erlang, at least, you can point to best practices – a recommendation to shove state into the Mnesia database rather than model stateful processes.

      Immutable messages is insufficient for stateless objects. It’s a good start, though.

      • Sorry if reviving this stale thread is gauche, but I’m doing some work right now in Erlang on this very theme—storing (nearly) all my state in a deductive database and using trees of Erlang supervisors and state machines for my domain’s concurrent processes (that’s the rest of the state). I came to this from a general distaste of aliased data, which to me seems a special case of one of the two hard things in programming (naming things and cache invalidation, after Phil Karlton).

        I take a checkpoint on the database before each external input and restore it afterwards if there’s an error; the specific process tree that fails is restarted via OTP’s mechanisms, and I let it fill in its little bit of state from the known-good data in the restored database (the active states of the FSMs and the currently-expected external inputs, for instance); though as soon as I can find a syntax-light way to do it, I’ll be systematically pushing that out to the database as well.

        The domain is an online strategy game, but that’s neither here nor there; I think that combining a deductive database with a programming model that treats processes as first-class (and where processes may yield and explicitly request certain external inputs, whether through `receive` or in the guise of a state machine) is an easy fit onto board and card games (nearly always defined as a tree of processes and a set of relations and tokens), realtime games (often described as interacting processes), and many applications (often described as concurrent hierarchical state machines with reference, again, to an external database).

Leave a reply to dmbarbour Cancel reply