Card 01/ 08

ConceptDifficulty: Intermediate3 min

Interpreter Pattern: Representing a Small Language as a Tree of Classes

Each grammar rule becomes a class, and a sentence becomes a tree you can evaluate.

The Interpreter pattern represents a small language as classes, one for each rule of its grammar, so that a sentence in the language becomes a tree of objects, and evaluating the tree evaluates the sentence. A grammar is the set of rules saying which sentences a language allows, such as "a rule is a condition, or two rules joined by and". This card covers the problem that calls for it, the intent, and when it fits.

The problem is a rule language handled as text. A shop lets its staff write discount rules such as total > 100 and member. Splitting the string on and and checking each half works until someone writes member and (total > 100 or code = SPRING), and the brackets, the order of and and or, and a not each need another special case in the string handling.

String handling, and a tree of expression objects

Without the patternthe rule is cut up as text

py
def applies(rule, basket):
    for part in rule.split(" and "):
        if part == "member" and not basket.member:
            return False
        if part.startswith("total > "):
            ...
    return True

Brackets and or need new branches here.

With the patternthe rule is a tree of objects

py
rule = And(IsMember(),
           Or(TotalOver(100), CodeIs("SPRING")))
rule.interpret(basket)

Each class evaluates one rule; nesting is the tree.

The Gang of Four state the intent as: given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language. The representation is the classes; the interpreter is a method, usually called interpret, that each class implements.

Interpreter is one of eleven behavioural patterns, the family concerned with which object does which part of the work, and how objects communicate.

The behavioural family, with this pattern marked
PatternWhat it does
Chain of ResponsibilityPasses a request along a chain of handlers until one handles it.
CommandTurns a request into an object that can be stored, queued or undone.
Interpreter (this topic)Represents a small language's grammar as classes and evaluates its sentences.
IteratorVisits the elements of a collection without exposing how it is stored.
MediatorRoutes the communication between objects through one central object.
MementoCaptures an object's state so it can be restored later.
ObserverNotifies many objects when one object changes.
StateChanges an object's behaviour when its internal state changes.
StrategySwaps one algorithm for another behind a common interface.
Template MethodFixes an algorithm's steps in a base class and lets subclasses fill some in.
VisitorAdds operations to a class hierarchy without changing its classes.
Interpreter

Use it when

  • A small language recurs in the program, such as rules, filters or formulas that users or configuration supply.
  • The grammar is small, with a handful of rules, and stays stable.
  • Speed of evaluation matters less than being able to read and extend the rules.

Avoid it when

  • The grammar is large, where a class per rule becomes hundreds of classes and a parser generator serves better.
  • Evaluation must be fast, where compiling the sentence to another form beats walking a tree.
  • An existing language already does the job, such as SQL, a regular expression, or JSON with a schema.

← → move through sections and cards