

Why I love Common Lisp and hate Java, part II – code examples - mck-
http://kuomarc.wordpress.com/2012/02/02/why-i-love-common-lisp-and-hate-java-part-ii-code-examples/

======
arthurbrown
This 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>

~~~
mck-
The 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?

~~~
arthurbrown
The 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.

------
spacemanaki
This 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-
I 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
I 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.

------
jsankey
Sigh. 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-
Yes, verbosity is exactly the point. In the comments section, somebody
actually wrote it.

~~~
jsankey
Verbosity 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
_Verbosity 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
I 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
Oh, 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.

~~~
jsankey
Yes, that is exactly the distinction I'm talking about. And I agree this is
something that's pretty difficult to measure, probably impossible to measure
precisely.

I completely agree also that the language can have an impact on the
abstractions you choose. Some abstractions are obvious in one language and
obscure in another. I wouldn't defend Java against a better example than in
the original post, it certainly has its weaknesses. But I find that most
examples just show bad Java code, not that Java itself is bad, which is not
enlightening and frankly becomes tiresome.

On a related note, I think a lot of people underrate the influence of tools on
code quality too. They might complain Java IDEs are a crutch that merely let
you work around the language's weaknesses. I think they're a lot more than
that -- when I start working in a seriously powerful IDE for the first time I
was surprised how much it influenced my coding. Powerful automatic refactoring
just makes it so trivial to do the Right Thing (give something a better name,
factor out a method, etc). Beforehand I would have said that all you need is
discipline to create code of the same quality without the IDE. Now I'd say
even discipline and good intentions have their limits.

------
it
It 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
Which 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))

------
ElliotSh
That'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-
Sorry 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.

