#162 Brainstorming notes: out-of-band references

brian Wed 5 Dec 2007

We started off with how does one big config file get deserialized into a tree of resources in the namespace? Then during runtime, we work with the individual resources stand alone. Eventually we want to save the entire configuration back to one file. How do we chunk them during load?

This is a fundamental problem in both relational and REST systems. In relational systems, we identify out-of-band data via a foreign key. In REST we identify out-of-band data via URI. However in both cases I want:

  1. my code to declare the expected type of the out-of-band data
  2. want to make the programmer experience easy
  3. want to cache the result of the URI for my working thread

To take an example (we assume the use of some keyword like ref):

class Issue
{
  ref User author
  ref Comment[] comments
}

Here is a case were Issue references author and notes out-of-band. In our REST architecture this means those objects are themselves other Resources. Under the covers in the SQL namespace, those URIs are actually foreign keys. In order to meet our requirements above we need:

  1. have storage space for the Uri, Resource, and the cached User/Comments (although one Obj field might be reused)
  2. provide API access to both the Resource and the obj (User/Comments)

The storage issue can be solved by the compiler and the ref keyword. The access API is trickier. We talked about using alternate syntax:

issue^author -> Resource
issue.author -> User  (shortcut for issue^author.obj)

Then code to update the author User resource might look something like this:

issue.user.something = 99
issue^user.save

That is a little weird - we are using two different operators to access the Resource or the what the Resource references. Where that approach fails us is when the object in question is the top level. Consider a method which just takes an Issue:

process(Issue issue) { ... }

But now I decide I actually need a reference to the Resource, because I want to save the Issue. Big problem because that ^ operator only works when accessing a field. So that leads us to desire bi-directional references - we want the Issue to have a pointer to its Resource. The logical way to solve that is have some type of mixin or class:

mixin Boxed { abstract Resource resource }
class User: Boxed {  override Resource resource }
class Issue: Boxed {  override Resource resource; ref User author }

So now I can rewrite the code from above like this:

issue.user.something = 99
issue.user.resource.save
process(Issue issue) { ...  issue.resource.save }

That is pretty clean and easy to write. Or if my Boxed method actually provided a save convenience:

issue.user.something = 99
issue.user.save
process(Issue issue) { ...  issue.save }

Another other idea discussed was to make Uri or Resource a generic such that User^ meant Uri/Resource to a User.

john Fri 21 Dec 2007

Notes from second discussion on refs and ORM.

ORM

For discussion purposes, I'll refer to an object that can be stored in an RDBMS as a persistable object.

  1. Persistable types must be annotated with the @serializable facet.
  2. Fields that are not persistent are annotated with the @nonserialized facet.
  3. Not all serializable objects are persistable. Serialized fields must either map to a database type or be a simple type that can be mapped to string.
  4. Complex inline fields will be flattened into the table definition. If an object has serializable fields that cannot be mapped to a database value type, it is an error condition.
  5. Additional ORM specific facets will be used to provide mapping hints to the OR layer.
  6. Foreign key fields will be of type Uri. The target type for a foreign key will be indicated by a slot facet. See below for the general inline vs. ref discussion.

The C# ADO .Net api is very similar to JDBC for accessing an RDBMS. After looking at that API, I definitely think we need to include support for prepared statements in the sql api. Next steps for the sql pod are to enhance the api to include prepared statements and then implement the .net support.

Refs

We continued our discussion on ref fields. A ref is a field that references another resource by uri. We were looking for a design that would allow the ref to be treated like its target type while also providing access to the uri and the resolved resource. In addition, we wanted to support caching of the resolved object for each thread. After much debate we backed off of what appeared to be too much complexity for too little benefit. Instead we decided on the simplest solution at the expense of strong typing.

A ref property is just a uri. The syntax for accessing the object is still concise thanks to wildcard object assignment and the dynamic invoke operator.

class DiscussionGroup
{
  String name
  String description
}

class Post
{
  Uri group
}

DiscussionGroup group = post.group.get();
String groupName = post.group.get()->name;

This approach is less seamless (seamful?) and that's a good thing as it makes it more obvious to a developer that accessing a ref property may be an expensive operation. At this point we've intentionally left caching up to the developer. We also discussed the possibility of auto-generating typed getters and setters. This was vetoed as not being the "fan way". I'm exactly sure what that means at this point, but I still think if we don't do something we'll be leaving developers to write their own boiler plate code for classes with ref properties.

Resource / Obj / ResourceObj

We discussed how to manage the relationship between resources and objects. Specifically, in order to have a simple, clean api we need bidirectional references between a Resource and the Obj that it wraps. We decided that this enabling the bidirectional reference was the responsibility of the class being wrapped. That is, the wrapped class must have a mixin (temporarily ResourceObj but a better name is imperative) that adds the Resource reference. A Obj of a type that doesn't have the mixin will not provide access to the Resource that wraps it.

fand / fog file

Finally we discussed the fand bootstrap issue and how to persist the "fog file" to the file system. We decided that there really isn't a single fog file, but rather the mounted namespace will be reflected by directories and files on the file system. Each mounted resource will have its own file.

fand/
  demo/
    services/
      wisp.fog
      db.fog
      sidewalk.fog
    dashboard.fog
    users.fog
    images/
      logo.png

For distribution and deployment we will likely implement support for installing the fog as a zip file (probably with a special extension) that is extracted on as shown above on startup.

Login or Signup to reply.