In an object-oriented design, you would typically run into a problem that screams "adapter!" when you have a class that consumes interface X and another class (Y) that does a similar job as all variants of X but which does not adhere to said interface. A common way of addressing this problem would be to introduce a new class, Z, that is a variant of abstraction X and delegates to Y.
As with all patterns, traces of this wisdom can be followed into what we software developers would consider to be antiquity: the seventies. It probably goes way farther back than that. In the case of mechanics, it's been around for as long as complex machines.
Compilers tend to have rigid concepts surrounding the syntax they process. For instance, in C, a block can only have as its children a certain number of things: statements, declarations of variables, etc. Inside a statement, you can do all sorts of things. For instance: you can assign an expression to a variable.
Let's imagine we have a grammar something like the following:
method:
"method" identifier "{" {statement} "}";
statement:
(variable_declaration | assignment | return);
variable_declaration:
"var" identifier ";";
assignment:
identifier "=" expression ";";
return:
"return" expression ";";
expression:
(identifier "(" ")" | identifier | expression "+" expression |
identifier "+=" expression | "(" expression ")" );
In this case, an expression allows you to do a lot of things. It allows you to invoke a method, sum two things together, reference a variable, increment a variable by some amount, or logically group a sub-expression.
Sometimes, however, an expression is not a means but an end unto itself. For instance, you may want to invoke a method in order to create a side-effect. In those cases, the expression is really doing the same job as a statement: it is a unit that declares a single step in an algorithm. The fact that we already have a way of describing such actions that we call "expression" is incidental.
Enter the "expression statement" - a very common feature in almost any language. An expression statement allows you to leverage all the expressiveness built into however you allowed expressions to be codified when building a first-class statement in an algorithm. Let's look at that in pseudo-grammar:
expression_statement:
expression ";";
So simple. So powerful. Now an expression can be used as a statement. As we expand the variation behind the "expression" interface, we automatically gain the ability to treat new variants as statements. In essence, this is a very early adapter pattern and evidence that patterns have been with us since the beginning.
Let's imagine we have a grammar something like the following:
method:
"method" identifier "{" {statement} "}";
statement:
(variable_declaration | assignment | return);
variable_declaration:
"var" identifier ";";
assignment:
identifier "=" expression ";";
return:
"return" expression ";";
expression:
(identifier "(" ")" | identifier | expression "+" expression |
identifier "+=" expression | "(" expression ")" );
In this case, an expression allows you to do a lot of things. It allows you to invoke a method, sum two things together, reference a variable, increment a variable by some amount, or logically group a sub-expression.
Sometimes, however, an expression is not a means but an end unto itself. For instance, you may want to invoke a method in order to create a side-effect. In those cases, the expression is really doing the same job as a statement: it is a unit that declares a single step in an algorithm. The fact that we already have a way of describing such actions that we call "expression" is incidental.
Enter the "expression statement" - a very common feature in almost any language. An expression statement allows you to leverage all the expressiveness built into however you allowed expressions to be codified when building a first-class statement in an algorithm. Let's look at that in pseudo-grammar:
expression_statement:
expression ";";
So simple. So powerful. Now an expression can be used as a statement. As we expand the variation behind the "expression" interface, we automatically gain the ability to treat new variants as statements. In essence, this is a very early adapter pattern and evidence that patterns have been with us since the beginning.