Slots

A special slot is required for handling what is called _proto in NewtonScript. We store the name of another table in a special slot, __cb_proto_. This name is either an absolute path to a prototype, /mount/local_data/models/myMailMessage, or a relative path, myMailMessage. In the latter case, we would just slap "/models/" in front of it, thereby looking up through the overlay driver that manages /models (and the other items in /). If you want to really specifically name a certain table as your prototype, you can do so, but are not required to do so.

Locating slots depends on what the path accessed looks like. I propose we add a special path token, known as "/@/". When "/@/" is encountered in a path, we use CAM lookup semantics to locate it. Without "/@/", path lookup is identical to that of your filesystem, nothing abnormal about it.

Say we have the path "/local/email/Casbah/MessageAboutCAM/@/From". The /@/ tells us to first look for "From" in MessageAboutCAM. If its not found, we follow the path in MessageAboutCAM/__cb_proto__ and look for From in that table. And so on up the tree. Because we are using /@/ we could also do something like "/local/email/@/Casbah/MessageAboutCAM/From", which creates for a very complex tree of data inside of prototypes.

When a new table/frame is created, we just set the __cb_proto__ slot, and all other values are left as is. We read them from our prototype, and set them on write only. (Thus saving space.) Changes are seen in children only if the children aren't shadowing a parent's slots. Any child can become a parent simply by having a new table/frame point to it through __cb_proto__.

By doing all method lookups through /@/ as well, we get methods which can be overridden at any point in the search path, including at the instance level (something not usually possible in systems such as C++). Although a child can override its prototype's slots, the programmer should document what is overridden (or will be overriden as the program executes), and what won't be. Thigns that are never overridden (by convention, not because they can't be) can be considered "class" variables, however remember that at any time a different programmer could shadow these simply by creating new frames holding only these values. In essence, we have a very powerful system here. And its very flexible.

I would imagine CAM would ride between CPI and Natroun. CAM would invoke Natroun to get data elements and look to see what is in a table, but Natroun need do nothing more. CAM will process all searches via "/@/", and will locate methods and hand them off to Oriel modules, so that Oriel need not worry about how to get a hold of the method, or where it came from.





The "inheritence" relationship is just a matter of
having a "special" slot referencing a certain object. Essentially, we get a
union mount of the two objects with certain rules for overridding. E.g.,

Parent object (the prototype/class) lives at (let's suppose)
/classes/quickNote and has the following (local) slots
Name:''
Date:''
Message:''
SendTo: <a script>

I want to make a new quickNote, so I
cbPut (/classes/quickNote new) at /local/noteToBarb

Essentially, I could store a "single" slot object at /local/noteToBarb:

Child Object:
Parent: /classes/quickNote

Now when I mount/get /local/noteToBarb, what I should *see* is:
Parent: /classes/quickNote
Name:''
Date:''
Message:''
SendTo: <a script>

That is the parent slots. But let's say I want to put 'Bijan" in the name
slot. The child Object *actually* looks like:
Parent: /classes/quickNote
Name: 'Bijan'

So when I get it I see:
Parent: /classes/quickNote
Name: 'Bijan'
Date:''
Message:''
SendTo: <a script>

Thus, whenever I assign a value to the child's slots, I create a new slot
in the child path and store the value there. Everytime I *read* from a
slot, I look first to see if it exists in the child, and then check the
parent, and so on. (Note, deleting a slot would work in a similar way.)

Now notice that the Parent slot is special *only* in that it determines
what other pathnames are "in" the "union mount". Presumably, not only can I
alter the parent, but I could (with due caution) swap in a different parent!

There is messiness, of course--reorganizing objects in the CVN will have to
be done with care, but that's a given.

The beauty of this scheme is that object composition/inheritence is
accompilished by overlay mounts (which entails the need for a rather fast
implementation of overlay mounts, but that, too, is a given ;)), which
means that we get a rather interesting meta-object protocal (MOP).

I.e., essentially, an overlay mount treats disparite paths as if they were
a single path. /local/stuff/bijan/ and /local/stuff/wes/ might get unified
as /local/stuff/. How the paths get merged and what shows up to whom is
exactly what we care about. In this case, wes, suppose that you and I both
want to store a file in "stuff" under "aFile". I.e.,
/local/stuff/bijan/aFile and /local/stuff/wes/aFile. The right thing to do
here is to give each of us our own file, but let us get at it by going
/local/stuff/aFile. Now, we might not want to share *anything* in
/local/stuff/, we might want to share only things which are different, etc.
These sorts of decisions are what one wants to face when thinking about
object models.

Just as one can define filters to conceal stuff in a path you don't want to
look at all the time (e.g., '.' files), so too you should be able to define
filters that conceal certain "boring" slots. Since, on this account,
"directory" paths and objects are one and the same, when you implent one
capability, you get the other free.

(*Gosh* I feel dirty. But in a *good* way! ;))

> Thus the only part of sec. 5 that I
>would want to save is "Every object has an attribute ([[XREF to CVN]]) that
>contains the names of its superclasses. This attribute will be either a
>string or a list of strings. The attribute's value is the name of the
>superclass or superclasses, in the case of multiple inheritance. This name
>is a path in the Casbah Virtual Namespace, i.e.
>/core/classes/mammels/Animal." Of course it is necessary to specify the
>exact name of this attribute.

I definitely agree that the prototype slot should specify the parent object
in an unambiguous way. Notice, of course, that, in principle, any object
can inherit from any other object. That we put certain objects in /classes
(or /models) is, in essence, a convention. Any reasonable techinque for
specifying relative paths should work for specifying one's parent.

However, it may well make sense to do this resolution in the IDE and
require fully qualified paths to be *stored*. I don't know. I would favor a
search hierarchy which when something like:

Search the current "Directory".
Search my currect directory's "classpath" (that's for you, Kendall!)
Search my parent directory, etc.
When I hit /, search /classes.
If I fail, I fail.

(Note that I'd favor inserting searching /classes before searching up my
current hierarchy.)
I was only really using "union mount" to highlight the indentification of
slot dispatch/look up with general path resolution (via overlay mounts).
Also, I was thinking of "union" as opposed to "intersection" or other
kinds of table merges/overlays.

I think the strength of my current approach is that objects become just a
special sort of "table" in the CVN. You can define your object behavior
simply by changing 1) what gets mounted in what, e.g., the child overlays
the parent and 2) general name clash resolution. In other words, the
behavior of path resolution & mounting behavior *is* the meta-object
protocal, and you can alter the semantics of your objects by chaning the
way a certain table gets mounted.

Now, clearly, one wants a *standard* object model most of the time. But if
we can get the MOP (i.e., overlay mounts) done right, we can safely defer
much of this. Even better, we can settle on a very simple object model and
let those who have more complex needs add the extra semantics.

> My point was that the format of the Parent slot is critical. The Parent slot
> *must* be the absolute path to the object's prototype; the documentation
> suggests otherwise. If we allow relative (i.e. ambiguous) paths in Parent
> slots, I predict utter chaos. 

Hmm. I don't agree with this. Much depends on the search method. In
Newtonscript, for example, there is a very clear search method (which I
think I gave a version of in my prior note/monograph).

>Which is why my point is:

> > However, it may well make sense to do this resolution in the IDE and
> > require fully qualified paths to be *stored*.

> Now we just have to get the docs and the rest of the world to agree with us.
> :-)

Note that I wasn't agreeing--yet! I was saying it *may* be desireable.

On the "base object model should be very simple" approach, I would
definitely agree with you. But if we get the MOP right, this will be
completely under your control.



> Scott Miller wrote:
> > Shouldn't the concept of instantiating a frame mean that the default
> > values are copied into the frame right then, so these kinds of problems
> > can be resolved.  Admittedly the reverse is true, that this behaviour is
> > also useful, but I can see many more instances where data would be
> > corrupted by these kinds of assumptions.

> I can see how both behaviours might be valuable.  What about allowing
> both somehow; attributes, or a freeze() method or something?

I believe Python solves both issues well.

Recall that one of the main reasons that NewtionScript (NS) _always_
tries to inherit attributes is to conserve memory.  We (Casbah, and
Python too) don't have that problem.  In Casbah we can always keep the
instance vars with the instance.

But what if you still _want_ inheritance (either proto or parent,
w.r.t. NS)?  Python has the answer to that too: whenever an attribute
is missing in the instance, Python calls the __getattr__ method and
lets it try to find the attribute.  The default __getattr__ method is
to attempt to find the attribute in the class (i.e. method lookup, but
also class vars), but we can use a prototype-style system if we
desire.

Recall also that ``aquisition'' is attribute lookup up the CVN chain.

Instantiation is the wrong place to solve this. If you copy your slots,
then  you lose the benefits of inheritence (on our current model). Note:
Templates are supposed to serve this function. When you "instantiate" a
template, you get a complete copy of the frame.

It's more severe if you consider that slots can contain code too. You
*want* shared behavior *until* you override it in the child frame.

Furthermore, as I pointed out to Wes, "dynamic inheritence" is going to be
an issue since you can always assign a new path to the _proto slot (or pop
a new object in the path referenced in the _proto slot).

Now, is it a good idea to do this a lot? No way! Obviously. Is it a big
deal such that we'd need to forbid it? I don't think so. Experience with
Self and Squeak suggest otherwise.

Note that the copying to a different Casbah system is a bit of a red
herring. Here's three alternative techniques:
1) "deepCopying" There are time when you want a copy to copy the whole
inheritence chain, so you either *do* that, or you make a mega-
standalone table containing all the slots from up the heirarchy.
2) Remote referencing. _proto (at least on copying the frame to a
different system) has an URI like reference. If you need something
from the parent frame, you get it from the original Casbah system
(probably via LDO).
3) Read-only/"sealed" prototypes. You could, in the base system, have
"read-only" prototypes so that they *couldn't* change from
system to system (of the same version). This would be analogous
to NewtonScript storing prototypes in Rom.

Point is, there are cases where *each* of these is desireable. I suspect
that a good chunk of the time, most inheritence is going to be *very*
local, i.e., in the same "application"/table. So migration of the app will
bring the relevant objects along with it.

Finally, there is a development pattern that I think is valuable.. You
start out stuffing things into plain old tables/frames. You start wanting
to share this *kind* of table with other scripts, so you document it. You
get tired of writing a subroutine in each script to generate this format of
table, so you make a template. You get tired of having to go back an
manipulate all your instantiated objects every time you change a template
so you make it into a prototype. Perhaps, for a variety of reasons, you
decide that it doesn't need any ad hocness at all, so you port the object
to, e.g., Java as a class.

This is bottom up programming in the classic style. See Paul Grahmn's "On
Lisp" for a description.

>  Admittedly the reverse is true, that this behaviour is
>also useful, but I can see many more instances where data would be
>corrupted by these kinds of assumptions.

I think that only experience will tell. It just doesn't seem to be that big
a deal in actual practice.

But, as I wrote earlier, if the unification of the path resolution stuff
and the meta-object protocal works out, then you will be free to tighten or
loosen or otherwise alter your object semantics, as your application
requires. The big advantage of the unification, is that object semantics is
just a matter of how you organize your tables & paths.