tlareywi wrote:It is true that this serves as a sort of documentation. However, it goes beyond that because documentation isn't part of the runtime system. A person may or may not read the documentation. Even if they do, they may still pass something unintended into the package that doesn't generate problems immediately but rather down the road during runtime at some point, making it difficult for them to determine a root cause. The motivation for typing interface points between packages is so that you can make some solid statement, enforced by the system, regarding what you define as valid input. If the interfaces are open to any input then you've effectively created a situation where you must anticipate any possible input a user of your package may provide. By typing your interfaces, you're not letting them pass in things that you don't anticipate and hence increase your code's robustness. Granted, this doesn't always matter but it does sometimes.
So, I'm still not sure what you are after, exactly:
- API enforcement
- Performance optimization
If you want the first, then doc strings are fine. And doc strings are
available in the runtime system. This is a big difference from other static languages or things like Javadoc that use special comment formats. Lisp doc strings are stored with the functions and variables that they document. Type "(DESCRIBE 'SYMBOL)" in a typical Lisp where SYMBOL is one of your symbols with a known doc string and notice the output. At least with SBCL, it's quite robust. Note that often the base CL API is compiled with doc strings removed to save space. We don't need the CLHS repeated online. The point is, doc strings work quite well to document APIs. There are even a few packages out there to automatically generate other forms of API documentation (e.g. HTML) from doc strings.
If you're interested in doing the second option, you can always check types with your own code. You don't need to declare anything to do so. In other words, you can write something like:
Code: Select all
(defun foo (bar)
(unless (integerp bar)
(error "BAR must be an integer"))
Finally, if you want performance optimization, that's when it really benefits you to declare types.
As a little background, I come from mainly a C++/COM environment building large applications. So some of my ideas I'm sure carry over from that. However, for the past year I've worked mainly with Lua, an interactive scripting language with functional features and dynamic typing (I've been learning Lisp in hopes that I could get the best of both worlds, and then some). A significant percentage of defects we've encountered in this code base arises from developers calling interface points, where the arguments are of dynamic type, with an unpredicted 'type' of argument. There are plenty of cases where the documentation is read but not well understood.
So I still don't see the benefit. In a C++/COM world, type mismatches cause big problems because operations are not type-checked. In Lisp, you can't accidentally add a string and an integer. When you try, you'll generate a condition and be dropped into the debugger. At that point you typically have a full stack trace and can quickly identify where things went wrong. If the same thing happens in C++/COM, you just get a mysterious crash and if you're lucky a core file to debug after the fact. If you're really up tight, you could type check every parameter in an API right at the first entry to the API, but I'm really not sure that's too useful in practice. If it was such a big problem, you'd see it being done in Lisp code all over the place, and that just isn't the case.
Anyway, I really hope I don't spawn a type system war (pointless) as that isn't my intention at all. There's a place for many different kinds of type systems. I just wish they'd bend to my will
I'm not hung up on type systems, so you aren't offending me at all. I'd simply suggest that if you really want to learn Lisp, that you try to not impose your C++/COM background on it. Instead, read lots of well-written Lisp code (I'd recommend Paradigms of Artificial Intelligence Programming
as a good start) and see what good Lisp programmers do. Programmers have been using Lisp for nearly a half-century and there isn't much that they haven't tried during that time, I would surmise. I have been constantly amazed that when I start thinking Lisp needs such and such, I quickly realize that either it already has it, buried in some corner of the CLHS, or I don't really need it.
Put another way, whenever you learn to speak another language, whether human or programming language, you know you have arrived when you master idioms. Idioms from one human language rarely translate well to another human language. Indeed, whenever you use an idiom from a foreign language, you typically speak it in the foreign language. I submit that's true of programming languages, too. So, rather than trying to translate C++/COM idioms into Lisp, try learning Lisp's idioms first.