Nice TWiki > Doc > LanguageComparisons > NiceVersusPizza > AlgebraicDatatype (r1.1) TWiki webs:
Dev | Doc | Main | TWiki | Sandbox
Doc . { Changes | Index | Search | Go }
I think that it would be very convenient to have access to good old algebraic datatypes in Nice, perhaps modified as described in this article: (Extensible Algebraic Datatypes with Defaults)

It should be allowed to do a switch on an algebraic datatype (otherwise there is no reason to include the feature ;-).

I would say that it is easy to implement this feature - one might be able to get away with a simple translation to existing language features: just introduce a new multifunction for each switch statement. But I might be missing something....

-- TorbenHoffmann? - 08 Jul 2002

A problem with swich statements is that they are closed: if you add a new case to your datatype, you have to modify all switches operating on this datatype. It seems the paper presents well this problem, and tries to solve it with default cases (I have only skipped through the first pages so far).

I think multi-methods nicely solve this problem. Let's try to see if something could be improved. Taking their example:

package expressions;

abstract class Expression {}
class Variable extends Expression { String name; }
class Lambda extends Expression { Variable var; Expression body; }
class Apply extends Expression { Expression function; Expression arg; }

Expression eval(Expression);
eval(v@Variable) = v;
eval(l@Lambda) = l;
eval(a@Apply) = apply(eval(a.body), eval(a.arg));

Expression apply(Expression, Expression);
apply(l@Lambda, v) = substitute(l.body, l.var, v);
apply(e1, e2) { throw new Error("Not a function: " + e1);

package numeric;

import expressions;

class Number extends Expression { int value; }
class Opposite extends Expression {}

eval(n@Number) = n;
apply(o@Opposite, n@Number) = new Number(value: - n.value);

package print;

import expressions;

String display(Expression);

package main;
import expressions;
import numeric;
import print;

display(n@Number) = n.value.toString();
display(o@Opposite) = "-";

(I choose Opposite instead of Plus for simplicity of implementation, but the idea is the same)

What do you object to this solution?

A small change could to to allow a shortcut for the definition of an abstract class and several simple subclasses:

class Expression = 
    Variable { String name; }
  | Lambda   { Variable var; Expression body; }
  | Apply    { Expression function; Expression arg; }

This would be equivalent to the first version, but somewhat easier to read. As for switch, I think method implementation is as elegant, and more general because of the possibility to add new cases. Objections?

-- DanielBonniot? - 10 Jul 2002

Thanks - you have enlarged my understanding of multimethods.

I can see how method implementation is more general due to the possibility of adding new cases, but I am missing one good thing about algebraic datatypes in connection with case statements: the compiler warns you if you have not covered all the types in the union. That forces you to update all over the place when you add a case to an algebraic datatype which has it merits and its demerits, admittedly.

In Nice, if you add a new case (a new subclass of the root class), the compiler will indeed warn you if this case is not covered by an existing implementation for each method. -- DanielBonniot?

As I was pondering over your answer I thought of something that might be of practical use: let the compiler generate information about how the functions handle the different sub-types of a specific super class. Eg, if you take the Person example from the tutorial you the compiler should generate the following information:

   worker -> worker
   person -> person

and if you add another person sub-class, say Manager, but do not create a display(m@Manger) function the compiler should output something along the lines:

   worker -> worker
   person -> person
   manager -> person WARNING: super function used.

Then you still have the flexibility of multimethods but regain some of the extra checks that is inherent in ML-style algebraic datatypes.

Keep up the good work. -- TorbenHoffmann?

Are you suggesting to display this information systematically when an implementation from a super-class is used? This situation might be new to functional programming people, but I think it is normal and desirable often with OO languages. However there are cases where you want implementation to be done for sub-classes. It is possible using the # keyword instead of @:

String display(Person);
display(p#Person) = ...;

Then if you declare a sub-class of Person, it is not matched by the implementation #Person, so the compiler enforces that a new one be given.

-- DanielBonniot? - 28 Aug 2002

Topic AlgebraicDatatype . { Edit | Attach | Ref-By | Printable | Diffs | r1.13 | > | r1.12 | > | r1.11 | More }
Revision r1.1 - 11 Feb 2003 - 13:34 GMT - TWikiGuest
Parents: WebHome > LanguageComparisons > NiceVersusPizza
Copyright © 1999-2003 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback.