[m-users.] Mercury style for OO style interfaces

Zoltan Somogyi zoltan.somogyi at runbox.com
Tue Sep 7 06:39:17 AEST 2021



On Mon, 6 Sep 2021 21:10:08 +0100, "Sean Charles (emacstheviking)" <objitsu at gmail.com> wrote:
> I am wondering what the most appropriate technique is to emulate the concept of an interface

Have you had a look at the chapter in the Mercury reference manual on type classes?
They are the closest analogue to the OO idea of an interface.

They *may* be what you are after, or they may not; I don't know. We use typeclasses
in the Mercury compiler, but they are rarely needed.

> Each translation process will have a common set of predicates to transform my AST
> into a different output form according to command line switches.

The Mercury compiler represents Mercury goals using a discriminated union type
that has different function symbol for each kind of Mercury goal, such as unification,
first order call, higher order call, conjunction, disjunction, if-then-else and so on.
The vast majority of the algorithms in the compiler consist of a set of predicates
whose bodies switch on the goal, with each arm of the switch handling one goal kind,
like this:

p(Goal, ...) :-
  (
    Goal = unify(...),
    <code for handling unifications>
  ;
    Goal = first_order_call(...),
    <code for handling first order calls>
  ;
    ...
  ).

Object oriented systems cannot do this, because they have no concept of an
algebraic data type. (Some are now trying to add it, in the form of sealed classes,
but they are only a clumsy approximation.)

Compilers can be viewed as consisting of N algorithms operating on M kinds of nodes.

Everyone agrees that using algebraic data types like this in a compiler results (roughly)
in compilers where each of N modules looks after one algorithm, with M-way switches
like the above, whereas the OO approach results in a compiler with M classes, one for
each kind of goal/expr/statement, with N methods.

In my opinion, the algebraic data type is much superior, because it has *cohesion*:
all the parts of a module work on the same task. In the OO approach, every algorithm
has its M components split among M classes, which just about always means M files.
And the N methods in each file usually have just about nothing to do with each other
save the fact that they operate on the same kind of AST node.

Then there is the fact that e.g. adding a new algorithm requires adding a new method
in every class, resulting in version system merges and/or conflicts with every other change.

Zoltan.


More information about the users mailing list