aboutsummaryrefslogblamecommitdiffstats
path: root/docs/object-system.org
blob: facdda0dd9289ef351ae1b84cf20a43e4a2c02d3 (plain) (tree)







































































































































                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        











                                                                                                           
* Goals
The object manager:
- works as a uniform interface to the resources exposed by the system;
- provides a consistent way of tracking usage and managing access to parts of the system.

* The Object System
An object is something that exists as a part of the RNT system. An object has a "type", which denotes what it represents, and "protocols", which denote what it can do. Programs do not interact with objects directly, but do so through a handle. An object keeps track of how many handles to it are currently open, this is its reference count.

A "protocol"[fn:1] represents the ability of an object to perform a given set of operations. For instance, an object that has a directory protocol can be seen as one that exposes an operation, =list=, that enumerates its children, and another operator, =open=, that, given a key, returns a handle to a specific child. Just like objects, programs do not interact with protocols directly, but do so through an interface. A handle is itself an interface, that, among other things, exposes an operation to retrieve interfaces to additional protocols of the object it represents.

As a convention, we can denote a protocol as an ML structure as follows:
#+begin_src ocaml
  module Directory : sig
    type t

    val from : Handle.t -> t option

    val list : t -> string list
    val open : t -> string -> Handle.t option
  end
#+end_src
In the example above, =Directory= is a protocol, and =Directory.t= is an interface. =list= is an operation that, given a =Directory= interface, enumerates the contents of the corresponding object. =open= is an operation that, given a =Directory= interface and a key, returns a =Handle= interface to the object associated with the given key, if it exists.

=from= is not an operation of =Directory= per se. Rather, it can be seen as a polymorphic operation belonging to =Handle= that, given a handle and a protocol, returns an interface to that protocol iff it is supported by the corresponding object.

It is convenient to refer to interfaces using the name of the protocol they belong to, so a "=Directory= interface" is simply a directory, and a "=Handle= interface" is simply a handle.

What, more concretely, is a =Handle=? A =Handle= is the following protocol:
#+begin_src ocaml
  module Handle : sig
    type t

    val into : t -> (protocol -> 'a option) -> 'a option

    val copy : t -> t option
    val release : t -> unit
  end
#+end_src

=copy= duplicates the handle, if it supports being duplicated. =release= releases the handle, decrementing the reference count of the object. No further operations may be called on a released handle.

# Should this be inside `Handle`?
=into= deserves some explanation. First, =protocol=, the type, is defined as an extensible variant:
#+begin_src ocaml
  type protocol = ..
#+end_src

Suppose we are to implement the =Directory= module outlined above. We can add a variant to this record, and use =into= to implement =from= in the following manner:

#+begin_src ocaml
  module Directory = struct
    type t = < list : string list; open : string -> Handle.t option >

    type protocol += Directory of t

    let from h = Handle.into h (function Directory o -> Some o | _ -> None)

    let list o = o#list
    let open o k = o#open k
  end
#+end_src

This gives us a way of implementing interfaces out of a corresponding OCaml object[fn:2]. We are, however, still missing a way of implementing objects themselves. For this, we first need to define what an object is, concretely:

#+begin_src ocaml
  module Object = struct
    type t = < reference : unit; release : unit; protocols : protocols list >
  end
#+end_src

How do we construct a =protocol=? Going back to our =Directory= structure, we may modify it slightly:

#+begin_src ocaml
  module Directory : sig
    type t

    val from : Handle.t -> t option

    val list : t -> string list
    val open : t -> string -> Handle.t option

    module Provider : sig
      type provider = < list : string list; open : string -> Handle.t option >

      val make : provider -> protocol
    end
  end
#+end_src

=Directory.Provider.make= provides a way of constructing a =Directory= interface out of an OCaml object. =Directory.Provider.provider= has the same structure as the concrete definition of =Directory.t= above, although the similarities should be treated as merely incidental. A handle can be instantiated out of an =Object.t= in the same way:

#+begin_src ocaml
  module Handle : sig
    type t

    val into : t -> (protocol -> 'a option) -> 'a option

    val copy : t -> t option
    val release : t -> unit

    module Provider : sig
      val make : Object.t -> t
    end
  end
#+end_src

We can then implement an object exposing a =Directory= protocol as follows:
#+begin_src ocaml
  class empty_directory = object (self)
    method reference = ()
    method release = ()

    method protocols = [Directory.Provider.make self]

    method list = []
    method open _ = None
  end
#+end_src

[fn:1]: This was originally called a "capability", but represented something different than the term "capability" in "capability-based security". In the latter, an object in our sense could be considered a capability.
[fn:2]: This could just as well have been a record of functions - there is nothing specific to the OCaml object system here.

* The Object Tree
RNT exposes its resources as a hierarchy of objects. The root of this tree is an object that implements, at least, the =Directory= and =Registry= protocols. A handle to the root of this tree can be obtained by calling =Kernel.ObjectManager.root=. =Registry= is declared as follows:
#+begin_src ocaml
  module Registry : sig
    type t

    val from : Handle.t -> t option

    val register : key -> Handle.t -> (unit, Concepts.Condition.condition) result
    val unregister : key -> (unit, Concepts.Condition.condition) result
  end
#+end_src
=register= and =unregister=, as implemented by the root of the hierarchy, allows components to register resources that can be retrieved by users of the system through the corresponding =Directory= interface. The handle passed as an argument to =register= must support being "copy"ed.

As a convenience, a =path= represents a pattern of traversal the object tree. The path ="system" @/ "branch" @/ "master" @/ "multigroup" @/ "universe" @/ this= represents the object that can be retrieved by, from a given reference point, "open"ing the child denoted by ="system"= on the given reference point, then "open"ing the child denoted ="branch"= on the retrieved object, and so on. Every traversal assumes that the object in question has a =Directory= protocol. The ability to construct and manipulate paths is implemented by the =Path= module:
#+begin_src ocaml
  module Path : sig
    type path

    val this : path
    val (@/) : string -> path -> path

    val lookup : Handle.t -> path -> Handle.t option
  end
#+end_src

=ObjectManager.lookup= is a convenience function that applies =Path.lookup= to the root of the object tree.