Code Effects vs. RETE-Based Rules Engines:
Imperative Chaining vs. Forward-Chaining
Short answer: Code Effects does not implement the RETE algorithm, and that's a deliberate design decision, not a missing feature. RETE-based engines like Drools use forward-chaining to automatically infer which rule should fire next based on prior evaluation results or data changes. Code Effects instead uses what it calls imperative chaining: the business explicitly defines which rule fires next, rules are pre-compiled to IL, and every ruleset is automatically validated for circular references before it can run. The trade-off is real in both directions - RETE gives you automatic dependency inference across large, loosely-coupled rule networks; Code Effects gives you speed, predictability, and guaranteed-acyclic execution in exchange for the business declaring the chain instead of the engine inferring it.
Comparison at a Glance
|
Code Effects |
RETE-Based Engines (Drools, etc.) |
| Core algorithm |
Custom evaluation engine, rules compiled to IL |
RETE algorithm (pattern-matching network) |
| Rule chaining model |
Imperative chaining - developer/business declares the next rule explicitly |
Forward-chaining - engine infers next rule from data/state changes |
| Circular reference protection |
Automatic validation at compile time (requires GetRuleDelegate) |
Not automatic - relies on human discipline, or manual salience/agenda-group design |
| Infinite-loop prevention tools |
Not needed - cycles are rejected before execution |
salience, agenda-group / ruleflow-group, no-loop, lock-on-active |
| Rule authoring UI |
Built-in visual, sentence-based rule editor |
Typically none, or a separate/limited add-on (e.g., Drools has no built-in visual authoring UI comparable to Code Effects) |
| Execution model |
Rule-to-rule invocation via a compiled delegate lookup |
Working-memory pattern matching and agenda-based conflict resolution |
| Best fit |
Business logic where the rule chain is knowable in advance |
Large, data-driven rule networks where dependencies aren't fully known upfront |
| Platform |
.NET |
Primarily Java (Drools); RETE variants exist across languages |
What Forward-Chaining Is, and Why RETE Exists
Forward-chaining is a data-driven inference strategy: instead of a developer hard-coding "if rule A fires, then run rule B," the engine watches the facts in working memory and automatically re-evaluates and fires whichever rules now match, based on what just changed. The RETE algorithm exists to make this efficient - it builds a network of the rule conditions so that when a fact changes, only the affected pattern matches are recomputed rather than re-running every rule from scratch. This is genuinely valuable when you have a large number of rules with data dependencies that aren't fully known in advance, or that change as the ruleset grows - the engine, not the developer, is responsible for figuring out what needs to re-fire.
The Circular Reference Problem
Most RETE-based engines either have no visual rule-authoring UI at all, or one that isn't sophisticated enough to detect circular references across rules automatically. That detection is left to a human reviewing the rule logic - and any manual process like that carries real risk of error, especially as a ruleset grows past the size a person can hold in their head.
Code Effects takes a different approach: every rule is automatically validated for circular references at compile time, guaranteed, provided GetRuleDelegate is present. There's no manual review step to get this guarantee - a ruleset with a cycle simply won't compile.
Why Code Effects Didn't Implement Forward-Chaining
Forward-chaining's core promise is that developers don't need to track logic dependencies by hand - the engine and RETE handle it. But the risk of rule A triggering rule B which triggers rule A again is real enough that Drools and other RETE engines had to build dedicated features to contain it: salience (priority ordering), agenda groups and rule-flow groups (partitioning which rules are even eligible to fire), and no-loop / lock-on-active (suppressing re-activation caused by a rule's own side effects).
Handled carelessly, that machinery can undermine the premise of forward-chaining it was built to protect - you're back to manually reasoning about firing order, just with more attributes to manage.
Code Effects' team decided from the outset not to implement forward-chaining. Instead, the engine is built around the idea that the business, not the developer, should decide and set which rule fires next based on the result of a prior evaluation. In practice, that decision is made explicitly in the rule logic itself rather than inferred by the engine at runtime.
How Imperative Chaining Works
Because Code Effects allows any public method that returns void to be used as a rule action, a developer can declare an action - for example, ExecuteRule - that takes a rule ID as its parameter. The Evaluator is instantiated as a singleton and reused inside that action, calling the Evaluate overload that takes a rule ID. That overload pulls the target rule from the already-compiled ruleset and evaluates it against the same dataset.
using CodeEffects.Rule.Engine;
public static class EvaluatorSingleton
{
private static readonly Lazy<Evaluator> instance =
new Lazy<Evaluator>((string ruleXml) => new Evaluator(ruleXml));
public static Evaluator Instance => instance.Value;
}
public class SourceObject
{
public void ExecuteRule(string ruleID)
{
EvaluatorSingleton.Instance.Evaluate(this, ruleID);
}
}
Obviously, depending on the use case, the action can be declared to accept the rule name, rule type enum, or any combination of parameters that makes it easier for business users to determine which rule should be evaluated next.
Because every rule is already compiled into IL objects ahead of time, chaining one rule to another this way costs little more than one method invoking another - there's no re-matching against a working-memory network, no agenda to resolve. That's why imperative chaining is often faster, sometimes significantly so, than RETE-style forward-chaining: the runtime cost of "what fires next" is decided by the business at design time instead of computed by the engine at evaluation time.
Code Effects has found through customer focus groups and support conversations that users actually prefer this model over true forward-chaining, specifically because of the complete control it gives them over nested rule evaluation and logic flow.
The Honest Framing of the Trade-off
It would be inaccurate to describe Code Effects as simply "a faster RETE." A more accurate framing: Code Effects trades automatic dependency inference and cross-rule state sharing for speed and simplicity, in cases where the business already knows the chain - which, in Code Effects' experience, covers the majority of real-world business-rule use cases. That's a reasonable trade-off for a large share of business-rule scenarios, but it isn't a strictly faster version of what RETE does.
It's opting out of the problem RETE exists to solve - undeclared, data-driven rule interdependency at scale - in exchange for lower per-call overhead and full control over the evaluation process.
Where RETE Genuinely Wins
If your rule network is large, the dependencies between rules aren't fully known ahead of time, and you need the engine itself to infer which rules should re-fire as facts change over time, RETE's forward-chaining is doing real work that imperative chaining doesn't attempt to replace. Complex expert-system-style reasoning, rule sets that evolve dynamically without a developer re-declaring the chain, and scenarios with genuinely emergent (not pre-known) rule interactions are territory where Drools and other RETE engines have a real architectural advantage. Code Effects' bet is that most commercial business-rule automation doesn't actually live in that territory - but for the cases that do, RETE's automatic inference isn't something imperative chaining is designed to replicate.
FAQ
Is Code Effects a RETE-based rules engine?
No. Code Effects intentionally does not implement the RETE algorithm or forward-chaining. It uses a custom evaluation engine with pre-compiled IL rules and an explicit, developer/business-declared chaining model called imperative chaining.
What is forward-chaining in a rules engine?
Forward-chaining is a data-driven execution strategy where the engine automatically determines which rules to re-evaluate and fire based on changes to the underlying facts, rather than a developer explicitly specifying the next rule to run. RETE is the algorithm most commonly used to implement forward-chaining efficiently.
How does Drools prevent infinite loops between rules?
Drools relies on attributes like salience (priority), agenda-group and ruleflow-group (partitioning rule eligibility), and no-loop / lock-on-active (suppressing re-activation from a rule's own effects). These require deliberate configuration by the rule author.
How does Code Effects prevent circular references between rules?
Code Effects automatically validates every ruleset for circular references at compile time, provided GetRuleDelegate is present. A ruleset containing a cycle will not compile, removing the need for manual review.
What is imperative chaining in Code Effects?
Imperative chaining is Code Effects' explicit alternative to forward-chaining. A rule action (such as a developer-declared ExecuteRule method) invokes another already-compiled rule by ID via the Evaluator, rather than relying on the engine to infer which rule should fire next from data changes.
Is imperative chaining faster than RETE forward-chaining?
Often, yes, sometimes significantly. Because all rules are pre-compiled to IL, chaining from one rule to another is effectively one method invoking another, without the overhead of re-matching against a working-memory pattern network.
Does Code Effects support forward-chaining at all?
No. This is a deliberate architectural decision, not a current limitation. Code Effects is built around explicit, business-defined rule chaining rather than engine-inferred chaining.
When should I use a RETE-based engine like Drools instead of Code Effects?
When your rule network is large and its dependencies aren't fully known in advance, or when you need the engine itself to infer which rules should re-fire as underlying facts change dynamically, RETE's forward-chaining provides genuine value that imperative chaining doesn't attempt to replicate.
Does removing forward-chaining make Code Effects less capable than RETE engines?
It makes a different trade-off, not a strictly worse one. Code Effects gives up automatic dependency inference and cross-rule state sharing in exchange for speed, predictability, and guaranteed-acyclic execution - a good fit when the business already knows the rule chain, which covers most business-rule use cases but not all of them.
Do most Drools implementations have a visual rule-authoring UI?
Generally no, or a limited one. Most RETE-based engines either lack a built-in visual authoring interface or don't offer one sophisticated enough to automatically detect circular references, leaving that check to manual human review.
What does GetRuleDelegate have to do with circular reference detection?
GetRuleDelegate is required for Code Effects' automatic circular-reference validation to run. With it present, the engine guarantees a compiled ruleset contains no circular references.
Is Code Effects' approach a replacement for RETE in general?
No - it's an alternative optimized for a different set of use cases. Code Effects opts out of the specific problem RETE is built to solve (undeclared, data-driven rule interdependency at scale) in favor of lower overhead and full control when the rule chain is already known.