Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • Can be highly optimised
    • Plain function calls could even be inlined, though much harder to combine this with dynamic dispatch
  • Highly intelligible and familiar
    • Debugger traces featuring stack frames are a powerful source of explanation

...

  • The definition within top-level option's events also gives rise to a top-level definition which is within events in the resulting component
  • The procedural API addListener, removeListener, fire both creates a support burden as well as a garbage burden - we are forced to create some kind of closure to close over the internal state required for this support
    • Although we note that the existing addListener/removeListener API is actually sufficient for configuration of complex model elements, and that actually operating them will always require some kind of external machine such as fireTransformEvent etc
  • The "unnamed namespace" can't really be supported cleanly. We had discouraged users from putting things there anyway
    • Note that FLUID-5948 describes a significant problem with the design of namespaces throughout the system - which has to be resolved as part of the route to normalising the "unnamed namespace" 

Chain as Element

Original chain definition:

...

This original use case suggests that we have a further space of requirements, which is also suggested by the fireTransformEvent workflow that we implemented for promise chains - that of subsetting the workflow at execution time. In that API, this makes use of the somewhat cumbersome filterNamespaces options that allows just some elements of the sequence to be selected for execution. This is not a very "open" API - in that its cost scales with the number of authors. More natural would be the ability to select custom "input" and "output" points for the workflow, and expect that the system would arrange that all points between them would be executed. This would handle our use cases within Kettle dataSources as well as with markup generation. However, it's unclear how this could be fitted in to a system which allowed completely free signatures. The "options" system for fireTransformEvent provides a clear place to put such per-request policy information. The way out of this is perhaps to allow the entire input argument set to be "wrapped" by some routes and not others. event.fire would be retained as a native entry point that allowed no space for policy, whereas we would then support a fuller element.operate(args, options) API that left space for them in arg 2. The declarative form of invocation would then then support options at every site where invocation was possible, in addition to args. At the cost of yet more garbage, we could accommodate this in our existing recordToApplicable utility.

Parallels with model relay definitions

There's a close analogy with the Model Relay definitions that can be attached to model material within our new ChangeApplier model scheme. These express dataflow elements where data is ingested from a named path within a document, undergoes some processing, and is output to another path.

The contrasts are:

  • An element operates only once (per cycle), and in one direction - whereas a model relay element may operate any number of times (during a transaction) and possibly in both directions
  • The output path for an element is derived from its namespace, and nested within a further segment named return, whereas the output of a model relay is configured via target and can be freely ranged over the model material. Whilst model relay rules can, like elements, freely range over the document for their input material (via IoC references within the body of the transform), they traditionally draw input from a distinguished path named source.
  • The "document" that an element operates on is considered immutable, to the extent that it is "write once" - similar to options material, once a value has been observed, its value cannot be changed. In contrast, model documents can be mutated indefinitely
  • The signature to element listeners is free, whereas model relay elements are Model Transformation transforms. Whilst free signatures are a possibility (via fluid.transforms.free) these need to be treated specially. There is an ontology of metadata applied to transforms, whereas element listeners are all arbitrary, uninterpreted functions
  • There is an explicit concept of sequence applied to elements - giving rise to the idea of special context references as previous and last - all the listeners in an element are sorted into a single, stable sequence before they are operated, whereas model relay rules operate in a free graph, triggered by model invalidation
  • Very cheap examples of elements (the analogues of invokers) could proceed in a way which is allocation free, whereas dealing with a model area via relay rules will invariably produce a lot of garbage

That said, there are routes through which we could close up the gap between these features.

  • As suggested above by the notes on megapayloadism, we could allow the sequence order for elements to be drawn up in a dataflow-sensitive way, as well as simply driven by the sequence induced by namespace-directed priority constraints. This eases the distinction between "namespaces" and "paths". Presently, an element outputs to a path derived from its namespace. As with model listeners, we could support a separate "path" entry which is "traditionally multiplexed" with the namespace, but can be configured separately.
    • Again note FLUID-5948 which will be needed to reform the role of namespaces, especially our current support for the "unnamed namespace"
  • We could reduce the costs of component construction such that we could make a more direct analogy between "a component construction" and "an element firing". Traditionally, after an element fires, its "model area" is wholly lost, unless it is exported to its exterior via a top.return directive - whereas the model area of a component is persistent. However, we could make an analogy between an element firing and a very short-lived dynamic component