The Expression Problem in Clump

In this document we propose a solution to the Expression Problem exposed by Dr. P. Wadler. This expression problem highlights the expressivness of a language when a set of data and behaviors must be extended separatly or not without doing any recompilation.

For this purpose we define three languages. The first language only contains numbers and a dedicated evaluation. The second language is the first plus the addition. Therefore the evaluation must be extended and in parallel a method providing a string representation is given. Finally we add the multiplication to the second language defining the third one. This extension is done for the data but also all the behaviors i.e. the evaluation and the string representation.

Language Level 1

interface IEval {
    int eval();
}
      

object Num {
    final int n;
    Num(int n) { this.n=n; }
}

class numEval(Num) implements IEval {
    eval() {
        return this.n;
    }
}

class main1(System) implements Main {
    start(args) {
        Num e1 = new Num(3);
        this.stdout().println("eval: " + numEval(e1).eval());
    }
}
      

Language Level 2

object Plus {
    final thistype e1, e2;
    Plus(thistype e1, thistype e2) { this.e1 = e1; this.e2 = e2; }
}

class plusEval(Plus) implements IEval {
    eval() {
        return self(this.e1).eval() + self(this.e2).eval();
    }
}

type Lang2 = Num | Plus

class lang2Eval(Lang2) extends numEval, plusEval implements IEval {}
      

interface IShow {
    String show();
}

class lang2Show(Lang2) implements IShow {
    case Num show() {
        return this.n.toString();
    }
    case Plus show() {
        return "(" + self(this.e1).show() + "+" + self(this.e2).show() + ")";
    }
}
      

class main2(System) implements Main {
    start(args) {
        Lang2 e1 = new <Lang2> Plus(new Num(3), new Num(2)); // thistype = Lang2
        this.stdout().println("eval: " + lang2Eval(e1).eval());
        this.stdout().println("show: " + lang2Show(e1).show());
    }
}
      

Language Level 3

object Mult {
    final thistype e1, e2;
    Mult(thistype e1, thistype e2) { this.e1 = e1; this.e2 = e2; }
}

class multEval(Mult) implements IEval {
    eval() {
        return self(this.e1).eval() * self(this.e2).eval();
    }
}

type Lang3 = Lang2 | Mult

class lang3Eval(Lang3) extends lang2Eval, multEval implements IEval {}
      

class lang3Show(Lang3) extends lang2Show implements IShow {
    case Mult show() {
        return "(" + self(this.e1).show() + "*" + self(this.e2).show() + ")";
    }
}
      

class main3(System) implements Main {
    start(args) {
        Lang2 e1 = new <Lang2> Plus(new Num(3), new Num(2)); // thistype = Lang2
        Lang3 e2 = new <Lang3> Mult(e1, new Num(2));         // thistype = Lang3 
        this.stdout().println("eval: " + lang3Eval(e2).eval());
        this.stdout().println("show: " + lang3Show(e2).show());
    }
}