[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

CLOS vs. subtypes of FLOAT



Here it is, finally, my proposal(s) for the treatment of the subtypes of
FLOAT for discrimination in CLOS.

The issue, to refresh folks' memories, is what to do with code like the
following:

	(defmethod foo ((x single-float)) ...)
	
	(defmethod foo ((x double-float)) ...)

There are three major questions:
  1) Is this code legal at all?  That is, is it okay to discriminate on
the
     subtypes of FLOAT?
  2) What is the effect of such code in an implementation that does not
     represent the two types differently (such as one that has only one
     representation of floating-point numbers)?  Is it legal in such
     implementations?
  3) Which of the symbols naming subtypes of FLOAT also name classes?
     Can this vary from implementation to implementation?

I have come up with three different proposals to answer these questions.
I will first lay them out and then discuss their relative advantages and
disadvantages.

Proposal 1 "NONE":
   It is illegal to discriminate on any of the subtypes of FLOAT.  None
of them name classes at all, in any implementation.
   
Proposal 2 "SOME":
   In a given implementation, exactly as many of the subtype-symbols
name classes as there are different representations of floating-point
numbers.  The ones that name classes are derived from the list of
allowable representation-naming schemes given on pages 18-19 of CLtL:
   -- If there is only one representation, then SINGLE-FLOAT names a
class.
   -- If there are exactly two representations, then either SHORT-FLOAT
and
      SINGLE-FLOAT, or SINGLE-FLOAT and DOUBLE-FLOAT, name classes.
   -- If there are exactly three representations, then either
SHORT-FLOAT and
      SINGLE-FLOAT and DOUBLE-FLOAT, or SINGLE-FLOAT and DOUBLE-FLOAT
and
      LONG-FLOAT, name classes.
   -- If four representations exist, then all four symbols name classes.
The classes named by such symbols are all subclasses of FLOAT.  Clearly,
those symbols that do not name classes cannot be used for
discrimination.

Proposal 3 "ALL":
   All of the subtype-symbols name classes, and all of those classes are
subclasses of FLOAT.  In some implementations, some of the classes named
by those symbols are "synonyms" for other classes, according to the
following scheme (again derived from pages 18-19 of CLtL):
   -- If there is only one representation, then the classes named by
      SHORT-FLOAT, DOUBLE-FLOAT and LONG-FLOAT are all synonyms for the
class
      named by SINGLE-FLOAT.
   -- If there are exactly two representations, then either
      - the classes named by DOUBLE-FLOAT and LONG-FLOAT are synonyms
for the
        class named by SINGLE-FLOAT, or
      - the class named by SHORT-FLOAT is a synonym for the class named
by
        SINGLE-FLOAT and the class named by LONG-FLOAT is a synonym for
the
        class named by DOUBLE-FLOAT
   -- If there are exactly three representations, then either
      - the class named by LONG-FLOAT is a synonym for the class named
by
        DOUBLE-FLOAT, or
      - the class named by SHORT-FLOAT is a synonym for the class named
by
        SINGLE-FLOAT
   -- If there are four representations, then no classess are synonyms
of others.
If a class A is a synonym of another class B, then A and B are not EQ,
they have different names, and they may have different metaclasses.  No
instances may exist of class A.  Defining a method on a generic function
F that discriminates on A has the same general effect as defining one
that discriminates on B.  However, if a method already exists on F that
discriminates on B or a different synonym of B (i.e., not A), then a
correctable error is signalled, allowing the user to choose which one of
the two methods will remain on F.


Under the NONE proposal, the pair of DEFMETHOD's above would be illegal
in all implementations.

Under the SOME proposal, the pair would be legal in those
implementations that had distinct representations called SINGLE-FLOAT
and DOUBLE-FLOAT.  In other implementations, an "Unknown class name"
error would be signalled.

Under the ALL proposal, the pair would compile and evaluate quietly and
correctly in those implementations that had distinct representations
called SINGLE-FLOAT and DOUBLE-FLOAT.  In other implementations, a
correctable error would be signalled upon encountering the second
DEFMETHOD and the user would have to choose between the two methods.


I have been convinced by conversations with a number of floating-point
users around here that algorithms exist that can go much more quickly if
they can be guaranteed a certain minimum amount of precision in the
numbers.  These algorithms would have to make checks for certain
conditions only if less precision is available.  While these programs
would have to be conditionalized (using #+/#-) for different
implementations to patch in the name of the sufficiently-precise
representation (since CLtL does not give a required bit count for each
representation), this isn't very hard to do and should be allowed.

One can also imagine users who wish to use the very same source code for
some floating-point-intensive computation in two methods, one for
SINGLE-FLOAT arguments and one for DOUBLE-FLOAT arguments.  The idea
here is that the compiler could generate much better code given the
implicit declaration of the argument type.  Each of the two copies might
perform much better than an undeclared version.  This user would be
letting the object system make a single check upon entry to the generic
function before dispatching to the representation-specific version of
the code.

I am convinced by arguments like these that reasonable uses exist for
discrimination on subtypes of FLOAT.  Thus, I believe that the NONE
proposal is a bad idea.

The SOME proposal is very easy to implement, but has the (perhaps only
aesthetic) flaw that the existence of classes for certain built-in types
would vary between implementations.  I find this notion disturbing and
would prefer not to see it.

The ALL proposal solves this problem but introduces, for almost all
implementations, the extra mechanism implied by the synonym classes.  It
may be that this could be very easily implemented, but Gregor would
probably know better.  An alternative to synonym classes would be making
the name -> class mapping be many-to-one.  Gregor claims that this
cannot be allowed, but I'm not sure that I understand why.  Another way
to avoid synonyms is to make the classes that would be synonyms into
subclasses of the other class.  This, on the other hand, has the problem
that methods defined on such classes would never be called, since no
instances of them can be created.  It also establishes an asymmetric
subclass relation for pairs with a symmetric subtype relation.


This is getting pretty long for such a relatively minor issue.  I'll
stop here and see if anyone can make any sense of this.

	Pavel