Subject: Re: MD5 in LISP and abstraction inversions
From: Erik Naggum <erik@naggum.net>
Date: Fri, 16 Nov 2001 20:53:45 GMT
Newsgroups: comp.lang.lisp
Message-ID: <3214932822476660@naggum.net>

* Bruce Hoult <bruce@hoult.org>
| 1) no one is forcing you to implement = and < for every class.

  But what does it mean to implement < for a new class, supposing for the
  sake of argument it was a generic function?  This remains unclear to me.

  (< a b c d) has a well-defined meaning for all real number types.  (It is
  less clear what it means for complex numbers, for instance.)  E.g., even
  though we most probably test only (< a b), (< b c), and (< c d), a true
  return value implies that (< a c), (< a d), and (< b d) are also true,
  and we are free to exploit this knowledge.  To make sure this holds for a
  user-defined type, it may be necessary to make those tests explicit,
  meaning that < becomes as expensive as /=.  (Some may not have realized
  that (/= a b c d) is not simply (not (= a b c d)).)

  We also know that (< a b) and (not (< b a)) is true for numbers, but
  because of generic function dispatch, (< a b) and (< b a) may be
  implemented by different methods, and it may no longer hold.  Even if we
  have an implementation of < that dispatches only on its first argument,
  this would be true.  It would also mean that (and (< a b) (< b c)) may
  yield a different result than (< a c) if only because of which method is
  called.

  The probability of creating a royal mess here is staggeringly high, as
  any C++ programmer who has tried to overload < will know, but no C++
  programmer will ever bother to see if a<c if he has done a<b && b<c.  The
  Common Lisp specification of < means that (< a b c) should check for it.

| 2) what if your class is a new representation for numbers?  Continued
|    fractions, say.  Surely it is useful to be able to add a method to
|    the < GF in that case?

  It may not be.  For instance, it may make sense to create a set of
  functions specialized for comparing the lengths of sequences such that no
  more cdr operations are needed on lists than absolutely necessary to
  determine the correct result.  (length< a b c) is then different from
  (and (length< a b) (length< b c)), not in value, of course, but the
  latter would defeat the whole purpose of this function.  A generic
  function that accepted any number of arguments would have to dispatch on
  the type of one or two arguments, and it would be most natural to
  implement it as a progression through the argument list, comparing two
  values at a time, unless one grasps the need to implement it like /=, but
  in any case, the convenience value of this general implementation
  technique would make smarter options much less likely to be implemented,
  and the likelihood of creating a mess that computes wrong values for the
  implicit would go way up.

  I think the notion of adding methods to a generic function for a purely
  mathematical function like < stems from a lack of reasonable builtin
  support for the necessary numeric types.  I mean, how often _should_ you
  need to add a new kind of number class to a system?  Rather than optimize
  for this extremely unlikely need, optmizing for the most likely need,
  i.e., using the existing number classes, seems like good engineering.

  If you really want to build an experimental system, you can do it with
  the package system, but you would of course not get the benefit of any
  type declarations unless you had access to the compiler environment.
  Franz Inc has done some work in that area.  It still appears to be one of
  the more complex things to experiment with and get reasonable performance
  out of at the same time.  If you have an incomplete number stack to begin
  with, you would need good support for user-defined number types, and C++
  has that, but the other way to optimize this situation is to get it right
  from the start, and I think Common Lisp did that, both in terms of what
  it made efficient and what it made possible with the package system.

///
-- 
  Norway is now run by a priest from the fundamentalist Christian People's
  Party, the fifth largest party representing one eighth of the electorate.
-- 
  Carrying a Swiss Army pocket knife in Oslo, Norway, is a criminal offense.