Andre van Tonder <xxxxxx@now.het.brown.edu> writes: > Understood. Is there a good reason to conflate eq?-behaviour with > field mutability, though. For comparison let me describe the design of type definitions in my language Kogut. I feel it's a bit similar to SRFI-76, considering that it was developed completely independently. The common form of a type definition is: type <type-name> = <constructor-name> <parameters> { <definitions> }; Parameters are patterns (similarly to ML and Haskell, i.e. an identifier matches any value and binds it to a constant). Definitions are arbitrary local definitions: constants, functions, mutable variables, lazy variables, dynamically scoped variables, references with custom behavior, expressions executed for side effects etc. The constructor is a regular function. When it's invoked, it matches arguments to parameters and executes definitions in the resulting environment. Definitions are scoped like proposed LETREC* in Scheme. The constructor returns an object with the given type tag, and which makes available to the outside names bound by parameters and definitions. A pattern of the form 'var <name>' matches any value and creates a mutable variable initialized to this value. A pattern of the form 'private <pattern>' is like '<pattern>', except that the names bound by the pattern are bound only in the appropriate lexical environment, they're not made available outside the object. A definition of the form 'private {<definitions>}' or 'private => <definitions>' splices the given definitions and similarly makes names they introduce private. There is also 'public'. A sequence of patterns may include '<pattern>...' once. The list of the rest of arguments is matched against this pattern. If the '{<definitions>}' part of the type definition is omitted, it's equivalent to '{}'. If the '{<definitions>}' part of the type definition is omitted and all parameters are identifiers, the type is called a record type. This has the following consequences: * RECORD is added as a supertype. * Generic functions for introspection are defined for this type: getting the constructor function from the object and getting the list of field names of the object. (Given an object and a field name, one can access the field.) * The default equality is not reference equality but the equality induced by the equality of the corresponding fields. This is done by having a specialization of equality for two objects of type RECORD. The type may still define its own equality in any case. * Similarly for hashing and showing as a string. * The function Change is made available for this type. It takes an object and a sequence of 'name, value' pairs, and returns a new object of the same type, with the given fields of given values, and other fields taken from the object. It's implemented once for RECORD. * There is a shortcut for making the type serializable. If the '{<definitions>}' part of the type definition is omitted and parameters are omitted, the type is a singleton type. The constructor is not a function but a constant. Also: * SINGLETON is added as a supertype. * A generic function for introspection gives the name of the singleton. It's used by showing as a string. * There is a shortcut for making the type serializable. After the type name, one can specify supertypes. They are used only by the dispatch of generic functions. It's the programmer's responsibility to ensure that they make sense, they don't influence the representation or behavior of the object. A group of definitions may include 'extend <expression>' once. The expression is evaluated. When accessing fields of the object being constructed, any field not mentioned explicitly among parameters and definitions is taken from this base object. The private name 'this' is defined implicitly in the scope of the definitions. It denotes the object being constructed. While the object is under construction, it signals an error when one tries to access its fields (definitions might not have fully executed yet). If the object extends another object, the private name 'base' is defined implicitly in the scope of the definitions, and it denotes the object being extended. There can be several cases of '<parameters> {<definitions>}' where the structure of the object depends on parameters. This is rarely used, it's mostly for completeness with multiple cases of a function. There are facilities for composing an object from reusable pieces instead of extending a complete object, which allows "methods" to call other "methods" on 'this' polymorphically, but I won't describe them here: they are too far from this SRFI. A symbol which begins with an underscore is local to a module. It allows to make fields which are available in functions external to the object but not to anybody which has access to the object. I tend to put only state variables among definitions, and any functions operating on the record are external instead. A more Smalltalkish style would define functions inside objects; note that they would be physically duplicated for each object. -- __("< Marcin Kowalczyk \__/ xxxxxx@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/