Alexander Lehmann wrote: Geoff Wozniak wrote:
Alexander Lehmann wrote:Please correct me if I'm wrong, but I thought that the major difference between "functions" and "methods" -- with respect to Lisp and/or CLOS -- was that for methods, CLOS first looks up the most suitable (specialized) version of a method in regard to the given parameters, whereas this need not be done for plain "functions"?
What you are calling methods are actually generic functions. Methods are simply function-like elements associated with generic functions. dlweinreb's point was that plain functions and generic functions can be used in the same manner, although the internals are quite different.
Thanks Geoff, then I've misunderstood dlweinreb's point. I know that "methods" actually aren't "methods" but "generic functions" in Lisp. Anyways -- what about the (possible) overhead that is needed for finding and jumping to the most suitable generic function in contrast to "ordinary" functions? I suppose there is some overhead, but I don't know for sure...
A note on the terminology: a "generic function" means a Lisp function that's implemented by "methods". A method and a generic function are not the same thing. This is made somewhat confusing by the fact that CLOS does not require an explicit "defgeneric"; the presence of methods causes it to be as if an implicit "defgeneric" form had been seen. I am generally a big fan of using explicit "defgeneric" forms, since that gives you a good single place to document the contract of the generic function.
Yes, when you call a generic function, CLOS has to find the appropriate method(s) to call, and in general this costs something. (The "jump" part is just a Lisp function call, so that's very fast.) The amount of overhead depends on a lot of things. There are different implementations of CLOS in the different Lisp implementations. (Many of them are forks of the PCL implementation, with improvements; some of them are not.) CLOS implementations do a lot of caching and pre-computing. The book "The Art of the Metaobject Protocol" explains how this works. Some CLOS implementations optimize certain cases, such as a generic function that has only one defmethod. (Since Lisp is dynamic, a second defmethod could get defined later, so such optimizations have to adjust themselves for that at runtime!) The only way to know the overhead is to come up with the specific case you're interested in, and measure it.
If using OOP is the right modularity for your program, you rarely have to worry about this overhead. The main exception is if you're in a performance-critical area (known informally as "an inner loop"). Then it's worth taking a look at the speed and seeing whether the overhead is a problem or not. But don't optimize prematurely!