Use of mirrors

In order to have mirror(s) of a Context applied to an Element
  • expressions which involve any Element field must be evaluated within given Context and
  • Element result of an expression must be used within that Context
It implies that if
  • a components is mirrored within a Context and
  • we want to use its mirrored counterpart
then
  • the object (its mirrored counterpart) must not be returned outside the Context where it is mirrored
  • any queries on this component must be run within given Context
  • the Element must not get mutated as that makes it lose all its Shadows history
The only way to use the mirrored version from outer Context is to inspect the component
  • using a visitor object
  • visitor has call back method(s) which get evaluated within a target Context
  • the result to be returned must be a primitive, or an object which is not mirrored within a target Context
Otherwise, if the component is returned outside the Context, then
  • the object is resolved to its previous identity - determined by the last applied mirror
  • the shadows stack is unwound
  • the mirrored counterpart gets resolved to its original
There is a way to return or pass an Element by value to a different Context, and to protect it from being mirrored or resolved
  • by creating an empty mutation
  • all its shadows history is lost
  • it has a new identity - therefore mirrors of its original don't apply to the mutation
  • it can't be unwound to any of its originals anywhere in Context stack
  • this method should be used cautiously

Restrictions

  • Elements must not receive or store any modifiable objects
  • No identity comparison
    • always compare Elements by value. Element objects serve as wrappers. They are created when needed.
  • no global variable neither class-shared (static) variables
    • Static final Element seeds are used. They get adjusted to local Context by special a method.
    • Elements can be stored in static non-final variables. However, these must not be used along with other Elements later, as that breaks some core engine assertions. Otherwise a less efficient mechanism would need to be used - e.g.for Context.equals().
  • Deep queries
    • using visitor mechanism
    • components are to be used within Context of their containers
  • ElementPures can't store any values dependent on other ElementPures. That's because any of them may be mirrored, with no change to other components. That would involve inconsistencies. Element can cache values based on other components, because these are Context-associated, and therefore no more mirrors can apply to them in given Context.
  • simple header in any non-static Element method - entered/up/dw

Mutations and Mirrors

Mutation creates ElementShadowed of entirely new identity. That implies:

Mutation loses all its Shadows history. The original Element could be a result of one or several applied mirrors applied to top-level seed. It can't unwind mirrors which were applied to original of the mutation. Otherwise the changes carried by the mutation would need to be applied to mirrored original as the Element is returned from local Context. What identity would it have? What mirrors would apply to it, and how?

When a mutation is passed down to a deeper Context, mirrors of mutation's original don't apply to the mutation itself. Otherwise mirrors would apply to almost any ElementShadowed of given type. That's because ElementShadowed instances of given class are supposed to be created as mutation of one or a few seeds of that type, or as their subsequent mutation.

TODO
Mirror [original, target] don't get applied to mutation of original Element. Otherwise that would involve dynamic mutation "combinations".

Compound (dynamic/adaptable) mutations/flexible mutations
SourceForge.net Logo Copyright (c) 2005, 2006, 2007 Peter Kehl