From: David Bakhash
Subject: defmethod & congruent arglists
Date: 
Message-ID: <cxjww0e4m3i.fsf@engc.bu.edu>
why do all methods of a generic function have to have congruent
arglists?

dave

From: Kent M Pitman
Subject: Re: defmethod & congruent arglists
Date: 
Message-ID: <sfwu2vh5uyt.fsf@world.std.com>
David Bakhash <·····@bu.edu> writes:

> why do all methods of a generic function have to have congruent
> arglists?

This question divides into two questions:

1. Why does the congruency requirement forbid certain configurations
   that seem conceptually to satisfy the congruency intent though
   not the letter of the rules.

Answer: I don't know.  I complained about this when it happened
 and no one seemed to care.

2. Why must a function take uniform calling conventions?

Answer: I *suspect* this is a hint that you are trying to do what I call
 "overloading" rather than what I call "genericity".  I use the former term
 to refer to accidental kludges that someone threw in because they had the
 bogus belief of generality. e.g., the use of "foo"+"bar"=>"foobar" in
 Java is and overloading issue in my personal terminology, not a genericity
 issue. In this case, the args are congruent and so congruency can be seen
 not to catch all such cases, but if you had a function named 
 PITCH that took no args to mean "throw a baseball" and one arg to mean
 "toss into the trash", then you'd have a congruency mismatch that was
 catching you doing the overloading thing that CL does not want you to do.
 Genericity it defined by the DEFGENERIC, for which there should be only
 one (or if multiple, they should be equivalent), and all the DEFMETHODs
 don't define the generic (except by the uninteresting favor they do you
 of doing an implicit ensure-generic-function (i.e., DEFGENERIC)).
 So what would it mean to have multiple ways to conform to a single way
 of doing things?  The defgeneric defines the protocol and that's the end
 of the story.  You can only redefine it or leave it the same without
 introducing overloading.

 The design comes from  (for example) Lisp Machine Flavors,
 where everything was 
   (SEND X0 :FOO X1 X2 ...)
 but this meant the compiler could never flag type errors or syntax errors
 because it didn't know what args X might take.  The change was made to
 do
   (FOO X0 X1 X2 ...)
 so that you could detect errors of argument type, number, etc.

 It is a good property of a language that its legal sentences are sparsely
 arranged because a compiler can tell good code from bad.  Lisp pushes
 the boundaries of this by declaring a great many things ok that are
 questionable in other languages.  But this is an area where a large body
 of programming showed that many bugs resulted from the availability of
 this flexibility you ask for and very little was lost by removing it.
 (This is why people like static typing--I just think they've carried it
 to extremes.  The ability to add static typing is good as an optional
 thing; the requirement to statically type is bad, IMO.  But it's this
 sparseness thing they're motivated  by in having the design.)

 Anyway, if FOO still just took &REST WHATEVER (which is what you are saying
 when you ask for no congruency checking, the compiler couldn't do that.)
 Every defmethod would be changed from
  (defmethod foo (...args...) ...blah...)
 to
  (defmethod foo (&rest args)
    (destructuring-bind (...args...) ...blah...))
 But then you also wouldn't know what to dispatch off of.  So the 
 system especially wants you to agree about the required args.
 If you allow 
  (defmethod foo ((x a) (y b) &optional z) ...blah...)
  (defmethod foo ((x a) (y b) (z c)) ...quux...)
 which of these will take precedence?  it's hard to know if this means
 the second replaces the first and the arg isn't optional, or if 
 the first merely replaces the "if supplied" part of the first, leaving
 the first equivalent to
  (defmethod foo ((x a) (y b)) ...blah...)
 and it's hard to know what to do with another method
  (defmethod foo ((x a) (y b)) ...antiblah...)

 Allowing different methods would also leave an ordering problem no
 different than the question of whether "foo1" is ordered before or
 after "foo" in an alphabetical ordering.  This is a definitional issue,
 not a conceptual one, so it's scary to make the core engine of your
 dispatch engine for function calls rely on something arbitrary like
 this.  By making all methods congruent, you implicitly make all methods
 have an intuitive ordering when competing for availability in an effective
 method computation.

I kinda typed that out quickly but I hope it's coherent enough for you
to slug through.
From: Barry Margolin
Subject: Re: defmethod & congruent arglists
Date: 
Message-ID: <HQuI2.367$p4.120288@burlma1-snr2>
In article <···············@engc.bu.edu>, David Bakhash  <·····@bu.edu> wrote:
>why do all methods of a generic function have to have congruent
>arglists?

See the thread that was posted the last time this was asked:

<http://www.dejanews.com/[ST_rn=ps]/dnquery.xp?search=thread&······························@milo.jpl.nasa.gov%3e%231/1&svcclass=dnserver>

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Thomas A. Russ
Subject: Re: defmethod & congruent arglists
Date: 
Message-ID: <ymiaex4nlda.fsf@sevak.isi.edu>
David Bakhash <·····@bu.edu> writes:

> 
> why do all methods of a generic function have to have congruent
> arglists?

How about 4 answers:

LEGALISTIC ANSWER:

  Because the ANSI standard says so.

IMPLEMENTATION ANSWER:

  Because methods of generic functions can dispatch on the types of more
than one argument.  In the interests of avoiding ambiguous cases, all of
the arguments that could potentially be used for method dispatch must be
the same across all methods of a generic function.

Motivating example:

If this were allowed:

  (defmethod f ((x INTEGER) &rest otherArgs) ...)              ;; F1
  (defmethod f ((x INTEGER) (y INTEGER) &rest otherArgs) ...)  ;; F2

then which is the correct method to use for a call to:

  (f 1 2 3 4 5)  ??

both F1 and F2 match.

Since you can provide keyword arguments, you can in fact have methods
that take different arguments.  The differences just need to be in the
keywords, not in the required arguments.

PHILOSOPHIC ANSWER:

Because all methods of a generic function are supposed to compute "the
same thing" in some general over-arching sense.  Computing the same
thing is a somewhat tenuous concept, but it motivates the desire to have
a common interface to the function.

One principle of object-oriented design is that if a program operates on
objects of type T, you should be able to use any subtype ST of T in the
same code and have the code function properly.  Now if the arguments of
a generic function F are not congruent, it would limit your ability to
substitute ST for T in the code -- since the method on F for ST could
take different REQUIRED arguments than the method on F for T.

If you have methods with this behavior, it suggests some potential
design problems in your program:
  (1) A flaw in the object type-subtype hierarchy, since the sub type is
      not in fact a good substitute for its parent.
  (2) A violation of the abstraction notion.  This is related to point 
      (1).  What it means is that the code in question relies on some
      particular property of the specific type of object.  This would
      indicate that the program isn't really concerned with doing a
      generic operation on a whole class of objects, but rather with
      doing a particular operation to some subset of this class.  In
      other words, the programmer already has to know which subtype
      of object he is working with, because otherwise he wouldn't know
      which set of arguments to give to the generic function.  This in
      essence forfeits the benefit of using the object abstraction and
      method dispatch in the first place.  Why not just use a
      non-generic function instead?  What benefit is gained from the
      generic function?
  (3) Conflation of two separate, but closely (?) related elements of
      functionality in the same generic function.  If there really is
      a difference in what is being processed, then perhaps there should
      be separate names for the functions.

SOCRATIC ANSWER:

How is this hampering you?  Do you have an example?


-- 
Thomas A. Russ,  USC/Information Sciences Institute          ···@isi.edu    
From: Harvey J. Stein
Subject: Re: defmethod & congruent arglists
Date: 
Message-ID: <m290cnubqf.fsf@blinky.bfr.co.il>
···@sevak.isi.edu (Thomas A. Russ) writes:

 > David Bakhash <·····@bu.edu> writes:
 > 
 > > 
 > > why do all methods of a generic function have to have congruent
 > > arglists?
<snip>
 > If this were allowed:
 > 
 >   (defmethod f ((x INTEGER) &rest otherArgs) ...)              ;; F1
 >   (defmethod f ((x INTEGER) (y INTEGER) &rest otherArgs) ...)  ;; F2
 > 
 > then which is the correct method to use for a call to:
 > 
 >   (f 1 2 3 4 5)  ??
 > 
 > both F1 and F2 match.

CLOS already says the most specific match wins, so it'd have to be the
latter.

-- 
Harvey J. Stein
BFM Financial Research
·······@bfr.co.il
From: Howard R. Stearns
Subject: Re: defmethod & congruent arglists
Date: 
Message-ID: <36FA4FDD.D20701EF@elwood.com>
Harvey J. Stein wrote:
> 
> ···@sevak.isi.edu (Thomas A. Russ) writes:
> 
>  > David Bakhash <·····@bu.edu> writes:
>  >
>  > >
>  > > why do all methods of a generic function have to have congruent
>  > > arglists?
> <snip>
>  > If this were allowed:
>  >
>  >   (defmethod f ((x INTEGER) &rest otherArgs) ...)              ;; F1
>  >   (defmethod f ((x INTEGER) (y INTEGER) &rest otherArgs) ...)  ;; F2
>  >
>  > then which is the correct method to use for a call to:
>  >
>  >   (f 1 2 3 4 5)  ??
>  >
>  > both F1 and F2 match.
> 
> CLOS already says the most specific match wins, so it'd have to be the
> latter.

Well, there's having the CLOS spec produce decidable algorithms, and
then there's having it produce efficiently computable ones.

It may or not be that one COULD compute an algorithmic ordering of
methods for all possible cases without needing concgruent arglists. 
However, it is not obvious to me how to provide even the most basic
caching optimizations without it.