From: Lowell Kirsh
Subject: refactoring in Lisp
Date: 
Message-ID: <c2j9at$62k$1@mughi.cs.ubc.ca>
I have run into some problems refactoring my code in CL. It really has 
to do with the dynamic nature of the language. In many other languages, 
when I change the name of a function but forget to rename it in one of 
the places where it's called, the compiler will let me know about it. In 
CL, it seems like the error won't be found until runtime when the 
computer tries to evaluate the function having the old name and can't 
find it any more.
What can I do to guard against this type of error? Are there any tools 
which could help me (i.e. lisp-lint) ??

Lowell

From: Barry Margolin
Subject: Re: refactoring in Lisp
Date: 
Message-ID: <barmar-118CD2.22072608032004@comcast.ash.giganews.com>
In article <············@mughi.cs.ubc.ca>,
 Lowell Kirsh <······@cs.ubc.ca> wrote:

> I have run into some problems refactoring my code in CL. It really has 
> to do with the dynamic nature of the language. In many other languages, 
> when I change the name of a function but forget to rename it in one of 
> the places where it's called, the compiler will let me know about it. In 
> CL, it seems like the error won't be found until runtime when the 
> computer tries to evaluate the function having the old name and can't 
> find it any more.
> What can I do to guard against this type of error? Are there any tools 
> which could help me (i.e. lisp-lint) ??

Many Lisp compilers warn about calls to functions that haven't been 
defined or declared.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Joe Marshall
Subject: Re: refactoring in Lisp
Date: 
Message-ID: <4qsylpuh.fsf@comcast.net>
Lowell Kirsh <······@cs.ubc.ca> writes:

> I have run into some problems refactoring my code in CL. It really has
> to do with the dynamic nature of the language. In many other
> languages, when I change the name of a function but forget to rename
> it in one of the places where it's called, the compiler will let me
> know about it. In CL, it seems like the error won't be found until
> runtime when the computer tries to evaluate the function having the
> old name and can't find it any more.
> What can I do to guard against this type of error? Are there any tools
> which could help me (i.e. lisp-lint) ??

tags-query-replace in emacs

-- 
~jrm
From: Kenny Tilton
Subject: Re: refactoring in Lisp
Date: 
Message-ID: <Vdd3c.32204$Wo2.3111@twister.nyc.rr.com>
Lowell Kirsh wrote:

> I have run into some problems refactoring my code in CL. It really has 
> to do with the dynamic nature of the language. In many other languages, 
> when I change the name of a function but forget to rename it in one of 
> the places where it's called, the compiler will let me know about it. In 
> CL, it seems like the error won't be found until runtime when the 
> computer tries to evaluate the function having the old name and can't 
> find it any more.

Of course it will find it, unless you have discovered fmakunbound, and 
that is a problem (happily running a function you renamed /and/ modified 
to behave differently). fmakunbound aside, Lisp won't forget name-1 
until you shut it down and restart and reload the calling code, at which 
time you should get a warning.

> What can I do to guard against this type of error? Are there any tools 
> which could help me (i.e. lisp-lint) ??

MCL has a "list callers" dialog. In ACL I use the files searcher to look 
for "(name-1". Crude but effective. Actually, methinks I once managed to 
hack up a who-calls function in ACL using some introspective functions I 
found. When I came over from MCL I really missed it. Now I just do the 
text search.

kt


-- 
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film

Your Project Here! http://alu.cliki.net/Industry%20Application
From: Coby Beck
Subject: Re: refactoring in Lisp
Date: 
Message-ID: <c2jt7d$q5i$1@otis.netspace.net.au>
"Kenny Tilton" <·······@nyc.rr.com> wrote in message
·························@twister.nyc.rr.com...
> MCL has a "list callers" dialog. In ACL I use the files searcher to look
> for "(name-1". Crude but effective. Actually, methinks I once managed to
> hack up a who-calls function in ACL using some introspective functions I
> found. When I came over from MCL I really missed it. Now I just do the
> text search.

IIRC, at least in ACL5.x there is a who-calls in the x-ref (xref?) package.
That package was great for finding special vars as well function calls.  It
must be in the 6x versions too...

-- 
Coby Beck
(remove #\Space "coby 101 @ big pond . com")
From: Frode Vatvedt Fjeld
Subject: Re: refactoring in Lisp
Date: 
Message-ID: <2hr7w2e54f.fsf@vserver.cs.uit.no>
"Coby Beck" <·····@mercury.bc.ca> writes:

> IIRC, at least in ACL5.x there is a who-calls in the x-ref (xref?)
> package.  That package was great for finding special vars as well
> function calls.  It must be in the 6x versions too...

There's even an edit-who-calls, pointing emacs to each caller of the
old function in turns. And there's a kill-definition command that
e.g. does fmakunbound of the old function name.

-- 
Frode Vatvedt Fjeld
From: Espen Vestre
Subject: Re: refactoring in Lisp
Date: 
Message-ID: <kwznaq8hu6.fsf@merced.netfonds.no>
"Coby Beck" <·····@mercury.bc.ca> writes:

> IIRC, at least in ACL5.x there is a who-calls in the x-ref (xref?) package.
> That package was great for finding special vars as well function calls.  It
> must be in the 6x versions too...

in LispWorks there's a very useful gooey thing that I use all the time,
and there's also a who-calls:

NFTP 55 > (hcl:who-calls 'trader:update-with)
((METHOD HANDLE-TRANSACTION (NFTPC)) (METHOD CAPI::INITIALIZE-INTERFACE :AFTER (CAPI-EXTENSIONS::NEW-WATCH-LIST)) RE-LAUNCH-STREAMER REGENERATE-MY-PORTFOLIO-WATCH-LIST (METHOD TRADER:UPDATE-WITH :AFTER (CUSTOMER-ORDER)) (METHOD TRADER:UPDATE-WITH :AFTER (CUSTOMER-DEAL)))
-- 
  (espen)
From: Rudi Schlatte
Subject: Re: refactoring in Lisp
Date: 
Message-ID: <m23c8i8se8.fsf@Rudi-Schlattes-Computer.local>
Lowell Kirsh <······@cs.ubc.ca> writes:

> I have run into some problems refactoring my code in CL. It really has
> to do with the dynamic nature of the language. In many other
> languages, when I change the name of a function but forget to rename
> it in one of the places where it's called, the compiler will let me
> know about it. In CL, it seems like the error won't be found until
> runtime when the computer tries to evaluate the function having the
> old name and can't find it any more.
> What can I do to guard against this type of error? Are there any tools
> which could help me (i.e. lisp-lint) ??

The unit tests you write in the process of refactoring will catch this
for sure.  (I'm assuming you use the term "refactoring" in Fowler's
sense; he devotes an entire chapter of his book on unit testing and
why it's essential for refactoring.)

Rudi
From: Kaz Kylheku
Subject: Re: refactoring in Lisp
Date: 
Message-ID: <cf333042.0403091317.73bc7dd0@posting.google.com>
Lowell Kirsh <······@cs.ubc.ca> wrote in message news:<············@mughi.cs.ubc.ca>...
> I have run into some problems refactoring my code in CL. It really has 
> to do with the dynamic nature of the language. In many other languages, 
> when I change the name of a function but forget to rename it in one of 
> the places where it's called, the compiler will let me know about it.

In many languages, your program won't even build. To make some
experimental change, you will have to edit so many places in the
program that it will effectively forbid you from certain types of
experimentatino.

Lisp's dynamic approach allows you to ``half refactor'' a program to
study the feasibility of some change, and then finish the job later.

The Meta-CVS project benefited greatly from this flexibility. For
instance when I added support for symbolic links, I changed a
fundamental data structure which broke most of the program. I was able
to fix just some core parts of the program to use the new structure,
build it and run the program in ways that don't step on the broken
parts. When I debugged the symlink support in these working parts of
the program, I gained confidence that I was doing it in the right way,
and then piece by piece I migrated the rest of the program.

That being said, decent Lisp compilers warn when they compile calls to
functions that have not been defined. Such warnings don't mean that
the function isn't defined; they might just indicate that the program
has been presented to the compiler in a such an order that the use of
a function precedes its definition (when functions mutually call each
other, this can't be avoided without making a dummy ``forward''
definition for one of them that is later replaced).

Or perhaps the definition is not presented to the compiler at all, but
will be present when the compiled module is loaded into the larger
program.  That's another useful flexibility. Lisp's association
between a symbol and function is a lot like linkage in some other
languages like C. A C compiler also cannot know that a function has
not been defined, only that it has not been declared! You can lie to
the compiler:

   extern int nonexistent(); /* decl */
   /* ... */

      nonexistent(); /* call */

This problem isn't caught at compile time, but at link time. But that
capability comes at a price: the linkage model is overly restrictive,
requiring a program to be built all at once. So in C programming
environments, we find various hacks for dynamic loading.

Once ``plugins'' in the form of dynamic libraries enter into the
picture, you no longer have the ability to catch undefined functions
at compile time.

Loading a shared library on UNIX via dlopen() or LoadLibrary() on
WIN32 can fail. Looking up a symbol in a loaded library via dlsym() or
GetProcAddress() can yield null. Fetching a COM interface can yield a
HRESULT of E_NOTIMPLEMENTED.

Dynamic features are so useful that platform developers will find ways
to hack them in when they are not part of the language.

> In 
> CL, it seems like the error won't be found until runtime when the 
> computer tries to evaluate the function having the old name and can't 
> find it any more.
> What can I do to guard against this type of error? Are there any tools 
> which could help me (i.e. lisp-lint) ??

I will mention something that I did not see among the existing
replies: the package system.

If your program is separated into packages, then what you can do is
remove the old name of the function from the package, or at least do
not export it.

When other places in the program try to refer to the name, there will
be a reader error.

   (foo-package::nonexistent-symbol 1 2 3)   -->  reader error!

This doesn't help you when the symbol is not referred to by a
package-qualified token, which is typically the case when the program
is all in one package.
From: Barry Margolin
Subject: Re: refactoring in Lisp
Date: 
Message-ID: <barmar-E16F24.16380109032004@comcast.ash.giganews.com>
In article <····························@posting.google.com>,
 ···@ashi.footprints.net (Kaz Kylheku) wrote:

> That being said, decent Lisp compilers warn when they compile calls to
> functions that have not been defined. Such warnings don't mean that
> the function isn't defined; they might just indicate that the program
> has been presented to the compiler in a such an order that the use of
> a function precedes its definition (when functions mutually call each
> other, this can't be avoided without making a dummy ``forward''
> definition for one of them that is later replaced).

I think most compilers that produce these warnings wait until the end of 
the compilation unit, so that mutual callers don't produce spurious 
warnings.  If the two functions are in different files, you can use:

(with-compilation-unit ()
  (compile-file "file1.lisp")
  (compile-file "file2.lisp"))

to try to suppress the warnings.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Christophe Rhodes
Subject: Re: refactoring in Lisp
Date: 
Message-ID: <sqishdyamt.fsf@lambda.dyndns.org>
···@ashi.footprints.net (Kaz Kylheku) writes:

> That being said, decent Lisp compilers warn when they compile calls to
> functions that have not been defined. Such warnings don't mean that
> the function isn't defined; they might just indicate that the program
> has been presented to the compiler in a such an order that the use of
> a function precedes its definition (when functions mutually call each
> other, this can't be avoided without making a dummy ``forward''
> definition for one of them that is later replaced).

This isn't quite true.  I'd regard any compiler which issued undefined
function warnings for
  (declaim (ftype function oddp))
  (defun evenp (x)
    (or (= x 0) (oddp (1- x))))
  (defun oddp (x)
    (evenp (1- x)))
as suboptimal.  (Of course, it would be nice if the compiler warned
about redefining CL functions and about the failure to cope with
negative or non-integral arguments ;-)

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)