Introduction
This article is composed of two parts. The first part explains the concept of “object algebras” using a toy example. The second part reuse the same toy example and extends it.
Object algebras
The expression problem, as presented in Oleksandr Manzyuk’s blog, is a way to offer the capability for a DSL to be extensible either in term of operations and in term of expression types.
After reading Extensibility for the Masses - Practical Extensibility with Object Algebras I decided to give it a look and tried to add a few more features to the example provided by the authors.
The architecture of the program is summarized in the following diagram :
PPrint and Eval are two operations which respectivelly pretty print a program and eval it to an integer.
|
|
ExpAlg and SubExpAlg are object algebra interfaces which can be used to define programs of the language. ExpAlg provides to operations lit(x: Int)
and add(e1: E, e2: E)
. SubExpAlg inherits from ExpAlg and add the notion of subtraction with the sub(e1: E, e2: E)
method.
|
|
The interpreters of the language are named object algebras. EvalExpAlg interprets ExpAlg programs and evaluate an integer.
EvalSubExpAlg inherits of EvalExpAlg and evaluates SubExpAlg programs.
PrintExpAlg evaluates EvalExpAlg programs and return a string representation.
Since both PrintExpAlg and EvalSubExpAlg are able to interpret SubExpAlg they are also able to interpret any language previously defined using ExpAlg.
This point is very important in language reuse. Using object algebras a developer
- is able to extend a language without modifications of the existing code base.
- know that any program written with a current version of an algebra will be interpretable as well with any future extended interpreters of the language
In conclusion of this section, an example of the usage of our languages.
|
|
Extending an Object algebra
In order to study the advantages and limitation of this approach we are going to extend the previously explained use case with the notions of boolean operations (&&, ||, ==, !). We will also offer a way to guaranty that the left and side and right and side of the ==
operator are of the same type.
Boolean operations
The first step is to create a language dedicated to the definition of boolean operation, the object algebra interface BoolExpAlg (the type definition might be hard to understand and will be detail in the next section).
|
|
We are now able to define the corresponding object algebras for boolean interpretation and pretty printing.
But first we are going to update the definition of the Eval trait and add a parametrized type.
|
|
By doing so we allow the object algebras of integer and boolean to share a common type.
Now that it done, here is the code of the object algebras.
|
|
For now we have a new language dedicated to the definition and interpretation of boolean expressions, completely decouple from our previous languages definitions.
An example of program in this language :
|
|
Language composition
We are now at a point where we can ask ourselves, can I mix easily my integer language with my boolean ?
I hope that the following program will proves you that the answer is yes !
|
|
Only by reusing the previously defined definitions and using traits compositions. We have defined a language supporting the evaluation of integer expressions, boolean expression and especially the evaluation of the equality of two integer using a boolean operator !
More details about the equality.
I wanted the equal operation of be type-safe. In other words in did not want the equal
operation to be able to compare apple and bananas (or integer and boolean).
|
|
But in the other hand I wanted my equal
operation to be extensible. Any new language with comparable elements must be able to reuse this operation easily.
To meet those two objectives the following pieces of code have been needed.
|
|
Conclusion
For now my opinion of object algebras is optimistic and even if the development of more complex DSL might lead to unexpected issues, the implementation of this small example have been surprisingly easy.
We can still observe that in order to add more flexibility we had to edit once a previously defined code. This is not mandatory and more verbose solution might be envisioned to do the same thing without touching any previously defined source code.
Also finding out a working definition of BoolExpAlg was not straightforward (but I am not an experienced Scala developer !).
The full code of the snippets found in the article can be found here : https://gist.github.com/manuelleduc/2607f15407017daf0d6ae9a987ece243
I hope this article gave you a first insight of the advantages and limitations of this approach of DSL definition and reuse.
Good reads
I have been introduced to the concept of object algebras by this awesome talk : “Using Object Algebras To Design Embedded Domain Specific Languages” by Julien Richard-Foy at Curry On'16.