5 ms·
Why I love Common Lisp and hate Java, part II – code examples
- it 15y agoIt can be written more concisely with fold. $ ghci Prelude> let getFromList ls pred = foldl (\x y -> if x `pred` y then x else y) (head ls) (tail ls) Prelude> getFromList [1..10] (<) 1 Prelude> getFromList [1..10] (>) 10
- semisight 15y agoWhich can be done just as well in lisps. The whole point was to show it in a way that didn't confuse the Java devs. ;Clojure example (defn get-from-list [list pred] (reduce #(if (pred %1 %2) %1 %2) list))
- jsankey 15y agoSigh. A good Java coder will also "get itchy" when writing two such similar functions. In fact, they'll probably already have a library that provides predicates that make the same level of abstraction trivial. Sure, the code in the predicate, being a whole class, will be a bit verbose, but that's a separate issue.
- mck- 15y agoYes, verbosity is exactly the point. In the comments section, somebody actually wrote it.
- jsankey 15y agoVerbosity is not as big a deal as operating at the right level of abstraction. It's much more important to adhere to DRY than to save a few lines of typing. Verbosity can harm readability, but not much in this case (I wouldn't use an anonymous inner class, so it's just a case of passing a GreaterThanPredicate).
- gruseom 15y agoVerbosity is not as big a deal Except that empirical evidence says it is a big deal: code size is the best measure of complexity we have, and error rates grow superlinearly with it. It's interesting how nearly everyone in the software profession pooh-poohs that finding. What we "know" (i.e., what we're used to) is more important to us than evidence. If we took the evidence seriously, we would work seriously to find ways to make smaller systems.
- jsankey 15y agoI take your point and I may be underrating the impact of verbosity. However, I think you're not quite addressing my point, which is that violating DRY (by not using high level abstractions) is worse than verbosity. Is it verbosity that is the best measure of complexity, or is it code size? Yes verbosity leads to more code, but it's not the only thing that does. Operating at the wrong level of abstraction also will, and in a way that makes maintenance extremely difficult. Unfortunately I've not seen any evidence compares the impact of boilerplate vs duplication.
- gruseom 15y agoOh, I see. You're making a distinction between two kinds of code bloat: the kind that comes from verbose languages and the kind that comes from duplication. I don't know of any way to separate these. Look at it this way: to make small systems, we need both powerful languages and good programmers. If you don't get to choose what language to write in (as is the case on most software projects), it's still better to write less code. But how can we measure the impact of language choice? I don't think we can. You'd have to write the system twice, holding the other variables constant. But writing the system once already changes everything. I don't disagree with you about the importance of good abstractions for reducing code size. Where we might disagree a bit is on the influence of programming language on what abstractions get created. It's fashionable in the industry to downplay the importance of language (algorithms matter more, libraries matter more, programmers matter more - pretty much everything is supposed to matter more). But I think the language we're writing in influences the kind of thing we write, and thus the kind of thing we think, all the way up to how we conceptualize the problem. Maybe it isn't the strongest influence at any point, yet it's compounded over every decision made in the lifetime of the system. Once a system has passed the embryonic stage, by far the most important factor in how it develops further is how the existing parts already work. Language seems to me deeply involved in conditioning this trajectory - why the system grows this way and not another. Not every idea is equally likely in every medium. I think we see this in the fact that distinct languages give rise to such distinct programming cultures. As an aside, this is something the typical way of comparing languages -- juxtapose a known algorithm written in X to the same thing written in Y -- fails to address.
- ElliotSh 15y agoThat's funny... I posted a few alternate java examples to his blog but it looks like the comment was rejected. (Perhaps because I said the lisp looked like vomit? but it does!) int getMax(int... list) { int max = list[0]; for (int i : list) max = Math.max(max, i); return max; } or if you have a collection Collections.min(list);
- mck- 15y agoSorry Elliot, but yes, that is why - you missed the point, just like you missed my Ugly Lisp code beware? The Lisp looks like vomit, because I wrote it with a Java mind. And for you to say that it looks like vomit, well.. I guess that's why ;) Your comment did not add any value to the discussion. However, it is emotionally loaded and might antagonize readers; I'd rather keep my blog clean.
- spacemanaki 15y agoThis is an bad example of macros; they're completely unnecessary here. The only thing you're stepping around is the already reader-macro shortened (function <). If you want to show off macros I think you should do it with something that simply cannot be done without them. Otherwise you end up with these pissing matches in the comments and the discussion diverges entirely away from metaprogramming to talking about characters or lines of code saved, which is kind of not that interesting. And Java vs Lisp is already kind of a tired topic. (Lisper and card carrying Java-hater here)
- mck- 15y agoI agree, and I am aware of it. I was about to get into another example to show something that only macros can do, but the post was getting too long. So please hang in there ;) I'm getting there. Also, there are different levels of audience. Diving straight into complex macro structures might just be ineffective. Above all, I'm not trying to preach to the converted. You seem to be well aware of the powers of Lisp, so not my intended audience. But thanks for reading and your input anyway ;)
- jwhite 15y agoI agree with spacemanaki. Your article introduces higher order functions, which is a big enough concept to keep those unfamiliar well-entertained without going a step too far and throwing in a not-particularly-useful macro. The last part of the article is an un-illuminating distraction. If I wasn't familiar with CL I would probably be scratching my head and asking why the hell that ugly #' is needed in the first place. More seriously though, your macro is dangerous as a teaching example because it introduces variable capture (on i and ans) and unintentional repeated evaluation (of list), which are big gaping traps for the unwary. Also, try passing #'(lambda (a b) (< a b)) as the pred argument to your macro, and see what happens.
- arthurbrown 15y agoThis doesn't feel like the author is trying to actually help Java programmers, but rather is just an excuse for him to patronizingly describe a language to those he considers less fortunate. I also don't understand the reason for writing the code in an intentionally non idiomatic style. If you want to convince someone why something is better; show them how it would be done properly. The way it has been presented instead insults the audiences intelligence by presupposing that they would be unable to understand this material, that the author has admittedly only recently picked up himself. I don't think (reduce min list) is going to blow anyone's mind, and writing a function to iterate through the indexes of a list will do more to confuse than to enlighten. not to mention; we've been here before haven't we - http://c2.com/cgi/wiki?SmugLispWeenie http://c2.com/cgi/wiki?SmugLispWeenie
- mck- 15y agoThe purpose of the author of the post was to introduce meta-programming to those ignorant of it. I see your point of insulting the audiences intelligence, but don't you think to throw in a tail-call optimized recursive function - or (reduce min list) for that matter - would be a moot comparison and distract the reader from the point? When you try to make a point by comparison, say the weather in Hong Kong versus Toronto, you wouldn't go gauge the weather in HK on a hot summer day at 4pm in the Central District, while in Toronto you go out in the burbs in the middle of a deserted, snowy night?
- batista 15y agoThe purpose of the author of the post was to introduce meta-programming to those ignorant of it. I'm not sure many Java programmers are ignorant about, say, the reflection APIs.
- arthurbrown 15y agoThe problem with "introducing" metaprogramming is that you first have to have a solid understanding of the language itself in order to manipulate it. From your examples in the article, I think that anyone who genuinely has no programming experience outside Java is going to have very serious problems understanding even the example you've given. Putting myself in those shoes, I have no idea what defun, let, do, when, setf, nth, length, and funcall are. I can assume they must be function names because they seem familar, but that still doesnt tell me how they should be called, how to give them arguments, what to expect they will return, or even how to know where they're defined. There's no way to teach someone how to programatically manipulate code if they can't mentally parse the code in the first place. Even if you were to completely teach Lisp as a language before introducing metaprogramming you still run into the experience issue. It takes personal experience to understand where and when to use macros. Like you said yourself in the article, most things can be expressed as a normal function. It takes the experience of writing a lot of code to be able to make the judgement of what actually belongs as a macro, and not just a function. I understand that metaprogramming is very exciting because it opens up so many doors, but it's easy to forget about everything that you had to already know to get to the point where it becomes useful. Lisp makes it very easy to repeat this problem because the language itself is so small and consistent. It doesn't take long to get to the point where you feel comfortable enough to try writing macros. It seems that you want to share how great metaprogramming can be and how much it simplifies the work you're doing. That's great, you and I can look at it and appreciate it. But framing it as though it's appropriate for Java programmers as an introduction to Lisp just serves to make Lisp programmers look arrogant, and builds even more resent amongst Java programmers.