A modest proposal ...
... to revive the extensibility mechanism.
Limited forward compatibility
A RIF dialect is forward compatible if a conformant implementation will process instances of any future or unknown extension according to the specification of the said extension (from the Extensibility section in the Architecture document).
This is probably too ambitious an objective to be tackled at this point. But what about limited forward compatibility?
Definition (limited forward compatibility). An extending dialect D provides limited forward compatibility to an extended dialect E, if D provides a fallback for all the specific cases where the semantics of a construct d that belongs to D but not to E, happens to be expressible in E.
An example is the Do construct in PRD that can be replaced by a Core And whenever it contains only Assert actions.
Implementing limited forward compatibility
Limited forward compatibility could be implemented by adding an attribute to all the RIF XML elements, say, rif:fallback, where the allowed values would be:
- reject, meaning that there is no fallback to the construct, and that an implementation that does not know the element must reject the document. reject is the default value for the attribute;
- ignore, meaning that an implementation that does not know the element can ignore it and its content;
- step-in, meaning that the proper fall-back for the element will be indicated by a sub-element, and that the element itself can be ignored by an implementation that does not know it, but not its sub-elements. If the element has no sub-element, then the fallback is ignore;
- any URL.
- If the URL is dereferenceable and if it dereferences to an XSLT stylesheet, then the fallback is the new RIF document that results from applying the transform to the original RIF document;
- If the URL is not dereferenceable or if it does not dereference to a processable XSLT stylesheet, then the fallback is reject.
- The fallback to Core for the negation in a RIF PRD condition formula is reject:
<NmNot fallback="reject"> content </NmNot>
- The fallback to Core for the RIF PRD Priority element is always ignore. Indeed, either the conflict resolution strategy can be ignored, and so does the priority associated to rules or group of rules; or it cannot be expressed in Core, and the document will be rejected anyway; or there is a way to rewrite the PRD document as a Core document with the same semantics, but without a conflict resolution strategy, and either the priorities will be removed during the rewrite, or they can be ignored anyway;
- The fallback to Core for the RIF PRD behavior element is step-in.
- In the first case below, the behavior element and all its content is ignored:
<behavior fallback="step-in"> <ConflictResolution fallback="ignore"> rif:forwardChaining </ConflictResolution> <Priority fallback="ignore"> 0 </Priority> <behavior>
- In the next case, the whole PRD document has to be rejected by Core implementations:
<behavior fallback="step-in"> <ConflictResolution fallback="reject"> ex:somePrivateCRstrategy </ConflictResolution> <Priority fallback="ignore"> 0 </Priority> <behavior>
- The fallback to Core for the PRD Do construct is a URL: http://www.w3.org/2005/rules/wiki/FallbackDo2And.xsl.
- An XSLT processor will remove the following fragment from a RIF document:
<Do fallback="http://www.w3.org/2005/rules/wiki/FallbackDo2And.xsl"> <actions ordered="yes"> <Assert> <target> assertion 1 </target> </Assert> ... <Assert> <target> assertion n </target> </Assert> </actions> </Do>
- and replace it with the following one:
<And> <formula> assertion 1 </formula> ... <formula> assertion n </formula> </And>
- the step-in and ignore fallbacks are not absolutely required, as the corresponding behaviour could be implemented with a simple XSLT transform. But using them may avoid unnecessary call to an XSLT processor, when a RIF document contains no URL fallback otherwise;
- the Do2And transform need not be conditional: a RIF Core implementation can replace a Do in a RIF PRD document with an And without pre-requisite. Either the Do contains only Assert actions and other constructs with a Core compatible fallback, and the RIF Core consumer will be able to process the rule (assuming that it contains no other non Core construct); or it contains some non tranformable non Core construct, such as a retract, the fallback attribute of that construct has value reject, and the implementation will reject the document as not being processable by a Core consumer;
- the fallback URL could be, but need not be, repeated in the <actions>, <Assert> or <target> elements, since a Core implementation will process the XSLT sheet because of the <Do> element anyway. Or should it be required, in case a clever implementation would look ahead for a reject fallback before calling the XSLT processor?
- Of course, there should be one single XSLT sheet containing all the transforms from one extending dialect to the extended one, not one per construct (e.g. Do2And etc) as the example may suggest.
Some constructs in PRD, such as Do, the behaviour and the binding pattern, do not exist in Core, but they can, in some cases (for Do) or in all cases (for pattern) be replaced by Core syntax with effectively equivalent semantics: a Do that contains only assertions can be replaced, in Core, by an And, without affecting the result; the behavior can, in some cases, be ignored; and the condition formula in a pattern can always be moved and added as a conjunct to the rule's condition.
It can be argued that this should be handled by RIF PRD producer implementations, which should produce Core compatible RIF-XML whenever possible, e.g. by using an And element instead of a Do when the action part of a rule contains only assertions, etc.
The argument in favor of such an approach is that the burden of additional implementation complexity should be on the party that requires the added expressiveness.
However, there are also arguments against requiring the implementers of the extending dialect to take care of the limited forward compatibility of the extended dialect:
- it does not scale well. PRD implementers may have only a few such exceptions to take into account to provide limited forward compatibility to Core, but the complexity of implementation is likely to grow wildly in future extensions with more "industrial strength" expressive power, as such exceptions will have to be taken into account in a cumulative way;
- Core-faction may change the behaviour of a rule set, even if it does not change the end result: I am not sure of that, but I think that we might find cases where transforming PRD action variables into Core-compatible rule variables may result in a non terminating behaviour according to the PRD operational semantics, without changing the end result. That risk, in that case or in some future dialect, calls for the transform from the extending dialect to the extended dialect to be done by the consumer, and only if required by the consumer, rather than by the producer, thus imposing it on all consumers, whether or not they need it;
- information is lost in the Core-compatible serialisation (or, generally: extended dialect compatible). Information such as that which is born by the binding patterns, for instance, may not change the ultimate result in terms of the inferred facts, but it certainly changes the behaviour of the rule engine, and might adversely affect the efficiency of executing the rules. In addition, such changes may obscure the intent or even meaning of the rules, once the RIF document is translated back into the consumer's rule language, thus affecting adversely communication as well as round-tripping.
Limited forward compatibility by way of explicit transform is scalable with respect to the implementation of RIF dialects: a dialect D that extends a dialect E has only to specify the fallbacks that provide limited forward compatibility of E with respect to D, and implemeters of D have only to care about the syntax and semantics of D (instead of having to take care of the limited forward compatibility with respect to D of E, and of all the dialects that are extended by E as well).
Of course, there is a cost: the interoperation outside the family of rule languages catered to by a dialect D (that is, the interoperation through a dialect that is extended by D) bears the burden that a RIF document may have to go through multiple transforms before being consumed, thus impacting the performance of the interchange negatively.
However, implementers can always choose to hardwire the transforms, when inter-dialect interoperation is foreseen as a major usage, and develop implementations for their extending dialects that produce RIF-XML that is compatible with the extended dialects whenever possible.
I believe that the first argument -- scalability -- is, by itself, enough for us to seriously consider reviving some form of extensibility mechanism.
But an important side benefit would be that it allows idiomatic syntax in extending dialects, thus making dialects more immediately appealing to their target audience, better adapted to intra-dialect interoperation, and, possibly, easier to implement; all this without renouncing anything on interoperability across dialects.
And, of course, the approach could be further extended later (I mean, in a RIF 2 WG; or 3, or 4...), with fallbacks affecting the semantics: fallbacks that crispify fuzzy or uncertain rules or terms by ignoring the certainty factors come to mind, for instance... Such fallbacks would need to provide some indication of the severity of the impact on the semantics, as Sandro suggested; and their application should not be automatic, but optional. Imagining such extensions make it even clearer why any transform to enable forward or sideward compatibility, limited of not, should be applied at the consumer, not the producer side (sideward, as in PRD/BLD).