Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

#36 handle CLOS warnings in a CLOSy way

closed-fixed
Sam Steingold
CLOS/MOP (1)
5
2007-11-23
2007-11-18
Sam Steingold
No

http://article.gmane.org/gmane.lisp.clisp.devel:17018
http://article.gmane.org/gmane.lisp.clisp.devel:17035
http://article.gmane.org/gmane.lisp.clisp.devel:17036
http://article.gmane.org/gmane.lisp.clisp.devel:17039
http://article.gmane.org/gmane.lisp.clisp.devel:17040

*warn-if-gf-already-called*
*gf-warn-on-replacing-method*
===>
WARNING
|- CLOS-WARNING
|- GF-ALREADY-CALLED-WARNING
|- GF-REPLACING-METHOD-WARNING

There is a reason, of course, but it is not in ANSI nor AMOP, because
these standards hardly address the issues of a development environment.

Both warnings are hints that something is wrong with the source code.

1) *warn-if-gf-already-called*
It's a hint that the order in which program files are loaded (order
of definitions, order of macro expansions, or similar) is wrong.

Example:
(defclass ware () ())
(defclass book (ware) ())
(defclass cd (ware) ())
(defclass dvd (ware) ())
(defgeneric add-to-inventory (object))
(defmethod add-to-inventory ((object ware)) nil)
(defvar *bible* (make-instance 'book))
(add-to-inventory *bible*)
(defvar *book-counter* 0)
(defmethod add-to-inventory ((object book)) (incf *book-counter*))
(defvar *harry-potter-7* (make-instance 'book))
(add-to-inventory *harry-potter-7*)
*book-counter* => 1

Since the bible and the harry-potter book were already added to the
inventory, the programmer might have expected that *book-counter* is 2.

2) *gf-warn-on-replacing-method*
It's a hint that different parts of the program, possibly developed
by independent people, are colliding.

Example: same code as above, then additionally:
(defgeneric sell (object price))
(defvar *book-sales-statistics* (make-hash-table))
(defmethod add-to-inventory ((object book))
(let ((stat (gethash (book-title book) *book-sales-statistics*)))
(unless stat (setf stat (make-stat)))
(stat-add stat 1 price)
(setf (gethash (book-title book) *book-sales-statistics*) stat)))

The programmer who programmed the first add-to-inventory@book
method expects that *book-counter* will be incremented. The programmer
who programmed the second add-to-inventory@book method expects
that *book-sales-statistics* gets augmented. If the implementation
gives no warning, one of the two programmers will waste time debugging.

That was the pragmatic, development-driven reasoning. The theoretical
reasoning behind it is as follows:

1) *warn-if-gf-already-called*
A generic function is defined by a contract. Whoever puts a method on a
GF, however, is also expecting a contract to be fulfilled. (In the
example above, it is that *book-counter* equals the number of invocations
of add-to-inventory on book instances.)
If the GF was already called before the method was installed, the
method's contract was definitely broken. Maybe the programmer has
foreseen this case (in this example: he could initialize *book-counter*
to the number of instances of book that exist at this moment, rather
than to 0), or maybe not. This is what the warning is about.

2) *gf-warn-on-replacing-method*
This warning can be warranted for the same reason as 1): If the old
method and the new method have a different contract, something is fishy
and possibly wrong, as in 1).
Additionally, the programmers may not even have intended to replace the
method. They may have intended cumulative effects of the two methods.

Of course, there are GFs, like PRINT-OBJECT, for which particular methods
have no different contract than the GF contract. On these GFs, the warnings
are pointless. But these GFs are a minority.

Bruno

Discussion

  • Sam Steingold
    Sam Steingold
    2007-11-23

    • status: open --> closed-fixed
     
  • Sam Steingold
    Sam Steingold
    2007-11-23

    Logged In: YES
    user_id=5735
    Originator: YES

    Thanks for the suggestion - it has been just implemented and
    checked into the CVS repository, and will be available in the next
    release.
    If you cannot wait for the next release, you can get the latest
    development sources from the CVS and compile them yourself.
    Please be aware that the development sources are not stable and
    might not even compile on your machine.
    You should report any problems you encounter with the CVS sources
    to the <clisp-devel> mailing list, not to the <clisp-list>.
    If you use the CVS sources, you should read <clisp-devel>
    since the CVS log goes there.