Scalable and Continuous

Marcin 'Qrczak' Kowalczyk qrczak@knm.org.pl
15 Feb 2001 07:44:40 GMT


Wed, 14 Feb 2001 23:27:55 -0600, Matt Harden <matth@ninenet.com> pisze:

> I also wonder: should one be allowed to create new superclasses of an
> existing class without updating the original class's definition?

It would not buy anything. You could not make use of the superclass
in default definitions anyway (because they are already written).
And what would happen to types which are instances of the subclass
but not of the new superclass?

> Also, should the subclass be able to create new default definitions
> for functions in the superclasses?

I hope the system can be designed such that it can.

> such defaults would only be legal if the superclass did not define
> a default for the same function.

Not necessarily. For example (^) in Num (of the revised Prelude)
has a default definition, but Fractional gives the opportunity to
have better (^) defined in terms of other methods. When a type is an
instance of Fractional, it should always have the Fractional's (^)
in practice. When not, Num's (^) is always appropriate.

I had many cases like this when trying to design a container class
system. It's typical that a more specialized class has something
generic as a superclass, and that a more generic function can easily
be expressed in terms of specialized functions (but not vice versa).
It follows that many kinds of types have the same written definition
for a method, which cannot be put in the default definition in the
class because it needs a more specialized context.

It would be very convenient to be able to do that, but it cannot be
very clear design. It relies on the absence of an instance, a negative
constraint. Hopefully it will be OK, since it's determined once for a
type - it's not a systematic way of parametrizing code over negative
constrained types, which would break the principle that additional
instances are harmless to old code.

This design does have some problems. For example what if there are two
subclasses which define the default method in an incompatible ways.
We should design the system such that adding a non-conflicting instance
does not break previously written code. It must be resolved once per
module, probably complaining about the ambiguity (ugh!), but once
the instance is generated, it's cast in stone for this type.

> What do you mean by mutual definitions?

Definitions of methods in terms of each other. Suppose there is a
class having only (-) and negate, with default definitions:
    a - b = a + negate b
    negate b = zero - b
When we make an instance of its subclass but don't make an explicit
instance of this class and don't write (-) or negate explicitly,
it would be dangerous if the compiler silently included definitions
generated by the above, because both are functions which always
return bottoms.

The best solution I can think of is to let the compiler deduce that
these default definitions lead to a useless instance, and give a
warning when both are instantiated from the default. It cannot be an
error because there is no formal way we can distinguish bad mutual
recursion from good mutual recursion. The validity of the code cannot
depend on heuristics, but warnings can. There are already warnings
when a method without default is not defined explicitly (although
people say it should be an error; it is diagnosable).

-- 
 __("<  Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/
 \__/
  ^^                      SYGNATURA ZASTĘPCZA
QRCZAK