That said (and I'm not trying to make this a "charged" statement ... just a way to learn more) I had always thought that one of the key things that made lisp so complete was that programs don't just crash ... that debugging is fully-baked into the *core* of everything. Now, I don't remember much about the debugging capabilities of, say, CL, but my understanding is that *after* a crash, you can interrogate the state of objects. . . .rather than having to preemptively guess at what you may want to know in the future.
This is largely down to CL's condition system: problems are usually reported as conditions, which stop execution without unwinding the stack. Unlike exceptions, you typically get a REPL in the environment of the condition (so you can view locals, inspect objects, etc.) — a bit like being "dropped into the debugger" in an IDE. Unlike an IDE, you can *do things* to the running program, and the condition often offers restarts (e.g., a "compile failed" condition might offer to retry the compilation). That means you can fix and continue, or just find out what went wrong.
These make an unexpected condition into an interactive process, rather than merely an opportunity for logging. By the time you were ready to ship your app, you'd experienced most of the failures, and introduced static or dynamic handling for those problems.
Unfortunately, Java can't match CL's condition system. There are steps towards including some of its power in Clojure (see errorkit).
That said, I still use tracing extensively in Common Lisp development: things might not crash, but I still need to see what's going on to identify the root cause of some high-level behavior. I also use print statements: often trace output is too verbose, or I need to see the result of some computation on an intermediate value. Sometimes there's no condition to raise.
Trace is better than logging. Logging just seems like a flawed approach (as others have pointed out). I mean, Log4j (or related) is desired in Java so that someone can get more information without a recompile. But in a dynamically run language or in an environment where you aren't just the user of some closed-off code, you may as well just put print statements where you need them. The latter is what I was advised to do in Clojure, and it was a real turn-off for me. Maybe the lack of appeal comes from having to squeeze in that extra "do" nesting -- or maybe because you then have to go through and remove all that stuff later. Or in the case of logging? you always leave it there, FOREVER. Even if you never end up caring about some state in a production environment!!!
I disagree that logging is a flawed approach. Tracing is an interactive tool. Logging allows you to see what happened before you were watching (which is important in the case of systems that are running for months or years, on many different machines, handling millions of requests). It also helps to produce a usable record of events in your program, which aren't always visible in trace output — e.g., "this request was invalid because this header appears to be truncated". Try spotting that in trace output.
-- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en