> <\body> The user may define new classes using the keyword >>. A simple example of a user defined class is the following: <\mmx-code> class Point == { \ \ x: Double; \ \ y: Double; \ \ constructor point (x2: Double, y2: Double) == { \ \ \ \ x == x2; \ \ \ \ y == y2; \ \ } } Declarations of variables inside the class correspond to declarations of the internal data fields of that class. In addition, it is possible to define constructors, destructors and methods (also called member functions). Declarations of variables inside the class correspond to declarations of data fields for that class. The data field with name can be accessed using the postfix operator . For instance, we may define an addition on points as follows: <\mmx-code> infix + (p: Point, q: Point): Point == point (p.x + q.x, p.y + q.y); By default, data fields are read only. They can be made read-write using the keyword >, as in the following example:> <\mmx-code> class Point == { \ \ mutable { \ \ \ \ x: Double; \ \ \ \ y: Double; \ \ } \ \ constructor point (x2: Double, y2: Double) == { \ \ \ \ x == x2; \ \ \ \ y == y2; \ \ } } Assuming the above definition, the following code would be correct: <\mmx-code> translate (p: Alias Point, q: Point): Void == { \ \ p.x := p.x + q.x; \ \ p.y := p.y + q.y; } Notice that the user may define additional postfix operators of the form outside the class, which will behave in a similar way as actual data fields. For instance, defining <\mmx-code> postfix .length (p: Point): Double == sqrt (square p.x + square p.y); we may write <\mmx-code> mmout \\ point (3.0, 4.0).length \\ lf; In order to be useful, a user defined class should at least provide one constructor. By convention, constructors usually carry the same name as the class, in lowercase. For instance, in the above example, the unique constructor for the class carried the name . Nevertheless, the user is free to choose any other name. In the body of the constructor, the user should provide values for each of the data fields of the class, while preserving the ordering of declarations. Constructors are also required to be defined inside the class itself. Nevertheless, the function name of the constructor can be overloaded outside the class. For instance, we may very well define the function <\mmx-code> point (): Point == point (0.0, 0.0); outside the class, which behaves as if it were a constructor. The default destructors for class instances are usually what the user wants in , except when some special action needs to be undertaken when an instance is destroyed (such as saving some data to a file before destruction). Destructors are defined as functions with no arguments and no return type using the keyword >. For instance, the following modification of the class allows the user to monitor when points are destroyed: <\mmx-code> class Point == { \ \ x: Double; \ \ y: Double; \ \ constructor point (x2: Double, y2: Double) == { \ \ \ \ x == x2; \ \ \ \ y == y2; \ \ } \ \ destructor () == { \ \ \ \ mmout \\ "Destroying " \\ x \\ ", " \\ y \\ lf; \ \ } } Special methods on class instances can be defined inside the class using the keyword >. For instance, a method for transposing the and coordinates might be defined as follows: <\mmx-code> class Point == { \ \ x: Double; \ \ y: Double; \ \ constructor point (x2: Double, y2: Double) == { \ \ \ \ x == x2; \ \ \ \ y == y2; \ \ } \ \ method reflect (): Point == point (y, x); } We may apply the method using the postfix operator : <\mmx-code> mmout \\ point (1.0, 2.0).reflect () \\ lf; Inside the body of a method, we notice that the data fields of the class can be accessed without specifying the instance, which is implicit. For instance, inside the definition of , we were allowed to write instead of , where > corresponds to the underlying instance which is implicit. Similarly, other methods can be called without the need to specify the underlying instance. Containers such as vectors or matrices can also be declared using the > keyword, using the syntax <\mmx-code> class Container (Param_1: Type_1, ..., Param_n: Type_n) == container_body As is the case of the keyword, the parameters are allowed to depend on each other in an arbitrary order, although cyclic dependencies are not allowed. The parameters may either be types (in which case their types are categories; see below) or ordinary values. For instance, we may define complex numbers using> <\mmx-code> class Complex (R: Ring) == { \ \ re: R; \ \ im: R; \ \ constructor complex (x: R) == { re == x; im == 0; } \ \ constructor complex (x: R, y: R) == { re == x; im == y; } } Notice that the user must specify a type for the parameter . In this case, we require to be a ring, which means that the ring operations should be defined in . Here is actually an example of a (see the chapter on categories for more details), which might have been as follows:> <\mmx-code> category Ring == { \ \ convert: Int -\ This; \ \ prefix -: This -\ This; \ \ infix +: (This, This) -\ This; \ \ infix -: (This, This) -\ This; \ \ infix *: (This, This) -\ This; } When introducing new classes, one often wants to define converters between the new class and existing classes. For instance, given the above container , it is natural to define aconverter from to . Depending on the desired transitivity properties of converters, there are three important types of converters: ordinary converters, upgraders and downgraders. We also recall that appropriate mappers defined using the > construct automatically induce converters (see the section about ). Ordinary converters admit no special transitivity properties. They are defined using the special identifier > and usually correspond to casts. A typical such converter would be the cast of a double precision number of type to an arbitrary precision number of type and : <\mmx-code> convert: Double -\ Floating; convert: Floating -\ Double; Upgraders usually correspond to constructors. For instance, with the example of the container > in mind, it is natural to define a converter from any ring to by> <\mmx-code> forall (R: Ring) upgrade (x: R): Complex R == complex x; This definition is equivalent to <\mmx-code> forall (R: Ring) convert (x :\ R): Complex R == complex x; In other words, upgraders are left transitive: whenever we have a type with a converter from to , then the upgrader also defines a converter from to . For instance, we automatically obtain a converter from to . In contrast to upgraders, downgraders are right transitive. Downgraders correspond to type inheritance in other languages such as C++, but with the big advantage that the inheritance is abstract, and not related to the internal representation of data. For instance, with the example class from the beginning of this section and some reasonable implementation of a class in mind, consider the class <\mmx-code> class Colored_Point == { \ \ p: Point; \ \ c: Color; \ \ constructor colored_point (p2: Point, c2: Color) == { \ \ \ \ p == p2; \ \ \ \ c == c2; \ \ } } Then the method provides us with a downgrader from to :> <\mmx-code> downgrade (cp: Colored_Point): Point == cp.p; Notice that this definition is equivalent to <\mmx-code> convert (cp: Colored_Point) :\ Point == cp.p; Given any converter from to another type , the downgrader automatically provides us with a converter from to . For instance, given the converter <\mmx-code> convert (p: Point): Vector Double == [ p.x, p.y ]; we automatically obtain a converter from to . In , instead of implementing pretty printing functions for new user defined classes, we rather defining flattening functions, which compute syntactic representations for instances of the new classes. More precisely, given a user defined class , the user can define a function> <\mmx-code> flatten: T -\ Syntactic; implements a default pretty printer for Expressions of type >. In fact, any type comes with such a flattening function. In particular, a default implementation is provided automatically when declaring a new class, but the default function can be overridden by the user. For instance, with the container as before, we may define aflattener for complex numbers by <\mmx-code> forall (R: Ring) flatten (z: Complex R): Syntactic == \ \ flatten (z.re) + flatten (z.im) * syntactic ('mathi); Here > stands for the standard name for the mathematical constant >, and addition and multiplication of syntactic expressions are provided by . The advantage of using the flattening mechanism is that takes care of some elementary simplifications when printing syntactic expressions. For instance, the complex number > will be printed as expected and not as something similar to |)>>. . If you don't have this file, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.> >