Joose blog

Blog about Joose – advanced class system for JavaScript

Archive for the ‘Internals’ tag

Joose 3 internals – Part II. Meta-model

without comments

This post will be very technical and contain a gory details about the implementation of the meta-model in Joose. It will be useful only for extension authors, if you are not planning to write one – nothing interesting ahead.

Well, you were warned.

Everything is a Property.

Property is the basement of the meta-model. It is an abstract name/value pair.

Everything in Joose is a property, i.e. attribute is a property, method is a property, role’s requirement is a property as well.

As it’s been mentioned in the previous post, property is implemented as a class from the 1st meta-level: Joose.Managed.Property (it has a Joose.Proto.Class as the meta-class).

Property can be shared among several classes (via composition relationships) so its totally self-contained and don’t contain any links to its “current” container, only to container it was defined in.

Property’s life stages.

By itself, property is just a description. To receive a concrete implementation (one can say “materialize” property) it should be applied to target. It can be un-applied as well (remember the mutability feature). In general, property has the following life stages: `preApply/apply` and `unApply/postUnApply`.  More on this below.

Everything is a PropertySet.

Joose.Managed.PropertySet inherits from Joose.Managed.Property. It is an abstract, unordered collection of properties, indexed by name:

On the set of property sets (sorry for tautology) we’ll define the following operations:

  • A.cleanClone – create a “clean” clone of A (without any properties)
  • A.clone – create a clone of A, including properties (only properties container will be cloned, not properties itself)
  • A.alias(what) – add aliases for properties, listed in what
  • A.exclude(what) – delete properties, listed in what
  • A.flattenTo(B) – for each property in A,
    • check if the property with the same name in B exists
      • if there is one, and its a special conflict marker property or the property of A itself, then just skip it
      • if there is one and its different from the above – then replace it in B with the conflict marker
      • otherwise, copy that property to B
  • A.composeTo(B) – for each property a in A,
    • check if B has own property with the same name
    • if not – then copy that property to B
  • A.composeFrom(B, C, …)
    • create a clean clone of A
    • flatten each argument into the clean clone (possible aliasing & excluding some properties first)
    • compose the result to A

Listed operations will implement the traits spec. All subclasses of PropertySet will keep the semantic of these operations.

PropertySet’s life stages.

PropertySet simply propagate the `preApply/apply/unApply/postUnApply` stages to its elements. Note, that current implementation is still written in the imperative spirit and rewriting it in more functional way will possible allow us to remove the `unApply/postUnApply` stages at all.

Mutable PropertySet.

Joose.Managed.PropertySet.Mutable inherits from Joose.Managed.PropertySet. Its a bit more specialized property set. It track the depended sets (derivatives) and propagate the changes through them. Mutable set B said to be the derivative of A, if it has been composed from A (possibly along with other sets).

Mutable PropertySet can be in 2 states: opened (this.opened > 0) & closed (this.opened == 0). Mutation is only allowed when property set is opened.

During “open” operation, when switching from closed state to opened the set is de-composed – cleaned from all properties which weren’t defined in this set. Before that all derivatives are also opened. Note, that the set can be opened several times – subsequent “open”s will be no-ops. Each “close” operation should have matching “open”. Initially the set is opened (this.opened == 1)

During “close” operation, when switching from opened state to closed, the set is re-composed using the data from “composedFrom” attribute and inherited “composeFrom” method.

Higher-order PropertySet.

Joose.Managed.PropertySet.Composition inherits from Joose.Managed.PropertySet.Mutable. Its an abstract higher-order mutable property set – a property set, which has other property sets as the elements:

Its no longer unordered and defines the order of properties processing (`processOrder`), also defines the reverse processing order, which is important for unapplying things.

Composition’s behavior.

Composition translates the higher-level operations to individual properties. That is, when composition A is asked to be flattened to composition B for example, it flat it’s individual properties:

Other operations are defined in the same way. Note, that composition is a mutable property set.

Stem

Joose.Managed.Stem inherits from Joose.Managed.PropertySet.Composition. Its a concrete implementation of composition:

Stem contains the following properties (in the processing order): [ ‘attributes’, ‘methods’, ‘requirements’, ‘methodsModifiers’ ]. Each of those properties is a property set of individual properties – collection of attributes, methods, etc.

Stem is the first property, which is aware of the real JavaScript class it belongs to (targetMeta attribute).

During re-composition stem initiates the `preApply/apply` actions of the whole properties subtree.  In the same way, during de-composition, it initiates the `unApply/postUnApply` stages.

Note, that during `preApply` stage the stem is still opened, and can mutate. During `apply` stage, the class definition is “final” and should only be somehow “materialized” in the prototype of the class, but not changed. The class in which the property should “materialize” itself will be passed as the 1st argument for “apply” method.

Conclusion

This post contains the details about the meta-model implementation in Joose3.  In the next post of this series we’ll briefly describe the anatomy of class from the 2nd meta-level – Joose.Managed.Class.

Written by Nickolay Platonov

January 13th, 2011 at 5:08 pm

Posted in Joose

Tagged with ,

Joose 3 internals – Part I. Meta-layers

with 3 comments

This post starts a series, describing the meta-model of the Joose3. It mostly purposed for people brave (or crazy) enough to hack on the internals, though casual users may find it also useful for deeper understanding of the underlaying processes in Joose.

Classes and meta-classes.

Ok, lets start with the definition what is the class. Its the abstract template or pattern, describing some behavior (for example: “Dog”). This template can be “instantiated” (usually arbitrary number of times) – that means the abstract definition receive a concrete implementation in some object (for example: “Pluto”). Such object will be called “an instance” of the class:

On the figure above and the following ones, the filled circles denotes classes, unfilled circles – instances.

Then, what is the meta-class? Its the class, whose instances, in turn, represents classes:

The meta-class defines the higher-level behavior of the class. For example it may define, that class can be only instantiated once. Or, that class may have special attributes with validation. Or, special methods with type-checking, etc.

Ok. You’ve probably already spotted the smell of recursion in the meta-class definition (its the class, whose instances are classes). Naturally, the chicken & egg problem arise – what is the meta-class of the meta-class itself? And what is the meta-class of that meta-meta-class?

Joose.Proto.Class – 1st meta-layer

The chicken & egg problem is being solved in Joose 3 by the 1st meta-layer, which is represented by the Joose.Proto.Class meta-class. Joose.Proto.Class is the class, which is the meta-class for itself! This makes its meta-instance perfectly circular – it refer to itself.

Classes with Joose.Proto.Class meta are very close to “raw” JavaScript and other simple class systems. Virtually everything from the class definition goes directly to the class prototype (except the “isa” builder). Inheritance is done with the “classical” prototype chain hack (see Joose.O.getMutableCopy in Joose.js)

If you really need “raw” JavaScript code (for animation library for example), you can host your class at this meta-level like this:

Class('Raw.Code', {
    meta    : Joose.Proto.Class,

    attr1   : 'init',
    attr2   : null,

    method  : function () { return 'result' }
})

var i = new Raw.Code()

i.method() == 'result' // true

At this meta-level there are no roles, traits, lazy attributes, method modifiers or any other magic, just JS. The other parts of the meta-model are written as classes from this meta-level. The next post will cover this topic in detail, in the meantime we’ll continue the overview of the other meta-layers.

Joose.Managed.Class – 2nd meta-layer

The next meta-layer is presented with Joose.Managed.Class. Joose.Managed.Class is a subclass of Joose.Proto.Class, and has it as a meta-class in the same time!


Important feature is that its safe to inherit from class, which has meta from the the previous layer:
This feature makes the bootstrapping possible.

Classes with Joose.Managed.Class as meta-class are already very capable. They may have method modifiers, roles or traits applied. At this level also appears the Joose.Managed.Role – a special meta-class, which, among other things, prevents class from instantiation.

However, we need one more bootstrapping step. The reason is that, by itself, Joose.Managed.Class has a Joose.Proto.Class as meta. Thus its behavior is very limited, you can’t apply role to Joose.Managed.Class for example. We definitely want our meta-model to have a more capable central meta-class. Another reason is the attributes. We need to be able to apply traits to the attributes. So the default meta-class for the attribute should be at least at “managed” level. But this level just been introduced – will be more elegant to delegate the change of the default attribute’s class to next layer.

Joose.Meta.Class – 3rd meta-layer

This is very simple meta-layer, required mostly for bootstraping purposes: Joose.Meta.Class.


There is also a corresponding Joose.Meta.Role meta-class.

Joose.Meta.Class is the central meta-class of the meta-model. If you need to modify the behavior of all classes, you can apply roles to it (comes in use for JooseX.Meta.Lazy for example). See also next section for explanations hows that possible.

Mutability

All classes in Joose, on all meta-levels are mutable. “Mutable” means that class/role definition can be changed at any time (add/remove attribute or method for example) and the change will be propagated to instances and other depended classes/roles.

Mutability is based on the fact, that during inheritance, prototypes of Joose classes forms the usual prototype chain. Thats why no special actions required when a class changes – the language itself will handle the propagation to sub-classes. A simple example:

var a = {

    method1 : function () { return 'a1' },
    method2 : function () { return 'a2' }
}

var b = Joose.O.getMutableCopy(a) // establish a prototype chain

b.method2 = function () { return 'b2' } // override a method

b.method1() == 'a1' // true
b.method2() == 'b2' // true

// mutation

delete a.method1
delete b.method2

b.method1 = function () { return 'b1' }
a.method3 = function () { return 'a3' } // add a new method to the base object

// eof mutation

b.method1() == 'b1' // true
b.method2() == 'a2' // true
b.method3() == 'a3' // true

Slightly more complex logic is required for roles mutations, but Joose never update the whole graph of depended classes, the most of work is delegated to JavaScript and  number of “manually” updated classes is as minimal as possible.

Conclusion

This post contains a high-level overview of the Joose meta-model. In the next post we’ll focus on the details of 2nd meta-level, which implements the traits specification.

Written by Nickolay Platonov

January 13th, 2011 at 9:02 am

Posted in Joose

Tagged with ,