7 ms·
Lisp vs Python
- bradleyland 16y agoI especially like the author's post script. Fortunately, this appears to be the prevailing attitude at HN.
- steve918 16y agoThis post has some interesting points, but I would really appreciate some concrete code samples.
- sigzero 16y agoWithout reading the article, can this be summed up as "People actually use Python"?
- delackner 16y agoIn general, any time you find yourself beginning to write a comment that says "I didn't read the article" is probably a good time to just click on the article, or go back to the news feed, or close the tab and move along.
- RiderOfGiraffes 16y agoNo. It's something entirely different, which you would know if you had read, or even just skimmed, it.
- mark_l_watson 16y agoI also agree with the author's post script. Both are good languages that while overlapping a bit are probably best for different types of projects. I use Python when I need an existing library like NLTK or simple web apps hosted on AppEngine, Common Lisp for research, some semantic web stuff, and general NLP. I use Gambit-C Scheme mostly to write small natively compiled command line utilities (mostly NLP stuff). It is all about getting stuff done, not insisting on using a favorite language, framework, or platform. Solving problems is what is fun and rewarding, not getting stuck on particular technologies.
- gnosis 16y agoRelated discussion: http://www.reddit.com/r/programming/comments/1ka0j/lisp_vs_python_syntax http://www.reddit.com/r/programming/comments/1ka0j/lisp_vs_p...
- softbuilder 16y ago>Python on the other hand has no macros I challenge this. I won't pretend that Python has full macro equivalence, but decorators are damned close.
- kenjackson 16y agoCan you expand on this. What is something that macros can do that decorators can't? And likewise, what are some common uses of macros that decorators can do?
- jerf 16y agoOne thing that answers both your questions at once are macros that create new control structures. Macros can take a chunk of syntax tree but not evaluate it, and decorators can only manipulate functions, they can't be used in a function. That said, the usual answers to the question of "Why do I need macros" are slowly but surely being chewed through by Python. The relatively-recent (albeit years old) addition of "with" took another previously-macro-only use case away. I'm not sure what massive win for macros is left. If your Python is "downright verbose" you're probably doing something wrong. It may not always be the Absolute Shortest (TM) but "downright verbose" shouldn't come up often.
- jfm3 16y ago>I'm not sure what massive win for macros is left. From my point of view, not being able to define new syntax is as serious a limitation as not being able to define new functions, or data structures. There are a number of specific examples usually cited to explain why the ability to define new syntax is important. Answering these specific examples by adding more static syntax to the language seems to be severely missing the point, to me. Imagine it was functions instead. "Well your language already has a sort() function, but say you want to use an in-place sort instead of what you get with the standard library? You need the ability to define your own functions." "No we don't, our BDFL added an in_place_sort() routine to the standard library for the next version of the language." That doesn't make sense to me at all.
- thurn 16y agoMany of the design choices in Clojure are aimed at resolving precisely these concerns. Quoted lists and literal lists are of course usually written '(f x) in most dialects, and Clojure uses [f x] for function arguments and binding lists. The only concern that remains is that (f x) could be a function call or a macro invokation. This is entirely by design, and is in fact a core idea of lisp that lets you build your own constructs with the same syntax as the language's native ones.
- intellectronica 16y agoSaying that LISP is for writing code and Python is for reading code is like saying that cars are for travelling uphill and bicycles are for travelling downhill.
- mkramlich 16y agoyou're right though, even if you thought you were making fun of it because that was the OA's point: that if a developer wanted to optimize for going uphill, choose a car rather than a bicycle. downhill? bicycle will do that with less resources, waste, cost, pollution, volume passed through, etc. pick which is better given the context and optimization goals.
- kenjackson 16y agoWhile you were being facetious, I do think that I'd love a device that turned into a bike when I was going downhill and then a car when going uphill. At the very least... a motorized bike for going uphill (which obviously do exist).
- mitko 16y agoThis is similar to the way I compare Python and Lisp: Common ground: first class functions, a lot of flexibility, closures Lisp: macros, performance? Python: easy to learn by example, readability, batteries included I use Python day-to-day as I don't really need a macro system that much. I also disagree that Lisp is more elegant - beauty is in the eye of the observer. Edit: formatting.
- euccastro 16y agoBeauty is subjective; elegance less so. Python is the language I've used and use the most, and I'll easily concede that Scheme is more elegant than almost anything else I've seen, and Python hardly even compares. Metaclasses, decorators, 'for'/'while'/'with' statements, etc. etc. In Python they are all good, practical, powerful ideas. In Scheme they're just unnecessary. Scheme is more elegant because it's been a priority in its design. Python aims to be more practical, beginner-friendly and straightforward.
- eru 16y agoTry Haskell. It has a strange mix of beautiful elegant core, and lots of (useful) syntactic sugar added on top.
- euccastro 16y agoI did try it, but not enough, I guess, to tell the beautiful core you talk about from the rest. So Haskell seemed to me full of elegant ideas, yet less elegant, as a whole, than Scheme.
- Locke1689 16y agoWhich Scheme are you talking about? I find the awful type system of base R6RS to be extremely inelegant. Contracts and strong typing make formal reasoning about programs far more powerful, hence more modern Scheme-style languages like Racket.
- stcredzero 16y agoThe trouble is that you can't easily tell just by looking at (f x) how to interpret it. Every serious development group is going to need a few patterns and coding standards, because newsflash: no language is perfect. All languages need to be used properly. If you have good standards for naming, then a simple search should tell you exactly how to read "(f x)" in less than a second. The same goes for Smalltalk method names. If an extremely important method in your application code gets named "add:" well, guess what, there are already base class methods named "add:"! This means your senders searches and implementor searches -- which are fundamental to the way lots of expert Smalltalkers code -- are going to be polluted. Also, the same thing can apply to function names in Python! In dynamic languages, good programmers know names are very important. Before a good, experienced dynamic language programmer names something "foo", they first search for foo! They search for things that might be confused with foo! Programmers of dynamic languages who don't do this are either ignorant or inconsiderate. This post doesn't strike me as written by someone experienced or knowledgeable with development in dynamic languages. (And if he's experienced, he's had the bad luck of having been mentored in short-sighted groups.) There's a lot of repetition and many times it's downright verbose. But where Lisp is nice to write and hard to read, Python makes the opposite tradeoff. It's easy to read. You can determine how to interpret something—a string, a list, a function call, a definition—just by looking at the code locally. This post takes no account of Don't Repeat Yourself and is seemingly written with no foreknowledge of this idea. Curious, since Python is powerful enough to get close to the ideal of Don't Repeat Yourself. Strategy for creating a blog post that looks analytical and sounds good -- but only to sophomore programmers: 1) Pick a certain aspect Y of language X which can be abused 2) Give a detailed analysis for why Y is bad 3) Completely leave out any mention of known best practices for addressing Y 4) Compare to a more popular language Z. Leave out any mention of Y applied to Z. This way, you can get some attention from sophomore programmers and provide them a way to feel better by giving them a good sounding reason to avoid studying X. Really, this kind of sophistry is so common, there should be a name for it! (Actually, there is a way that Lisp can be easy to write and hard to read, but that has to do with macro expansion. But the tendency is for those with substantive Lisp experience to know about things like that.) EDIT: To avoid distracting "ad hominem" nonsense. Note the argument is completely the same. EDIT: Got read/write mixed up.
- 16y ago
- jfm3 16y ago"Sometimes (f x) is [one of 6 things]" I don't mean to be the next snarky Lisp guy in the room, but I don't see the difference between reading (if (= a 3) ...) and thinking "that's a special form and a predicate", and reading if a == 3: ... and thinking "that's a special form and a predicate". In either case there's "if". Writing "(f x) could be anything" is a straw man. As soon as you replace "f" with "if" the argument falls apart. (No, you can't name a function "if" in Common Lisp. Go ahead, try it.)
- Jach 16y agoAh, but you can in Scheme. :) guile> (define if (lambda (. args) (display "Haha!") (newline))) guile> (if (= 3 4) 't 'f) Haha!
- jfm3 16y agoCute! And you're right! Scheme should be kept away from people who are prone to hurt themselves, as well as nail clippers and letter openers. Too dangerous! :)
- j_baker 16y ago> Lisp seems to be optimized for writing code; Python seems to be optimized for reading it. Urgh... A hundred times no. I really do appreciate that the author seems to have given Lisp a try. But this is simply wrong. Why does Lisp provide macros? Because they make code easier to read. I say stop focusing on what language abstraction (f x) represents and focus on figuring out what the code is doing. Oh well, at least he didn't complain about lisp having too many parenthesis.
- Teckla 16y ago"Oh well, at least he didn't complain about lisp having too many parenthesis." Humans are visual creatures. It really is easy to get lost in Lisp's parentheses. Languages whose blocks are easier to identify at a glance really are easier to read. The attitude of far too many Lisp developers seems to be that Lisp has failed to dominate after all these many decades because people are just too stupid to realize how great Lisp is. If Lisp hasn't dominated by now, rather than arrogance and superiority, it would be better to think about why Lisp continues to fail to dominate. By the way, I'm not suggesting you're one of those people.
- silentbicycle 16y ago> Languages whose blocks are easier to identify at a glance really are easier to read. Which is why conventions for indenting Lisp code to show block structure have been established for decades. This problem has been solved for longer than Python has even existed. I don't know why people keep bringing it up. Lisp isn't perfect, sure, but this is a very weak criticism. Besides, what about mismatched delimiter problems in languages like C that have shift-reduce conflicts? Dangling else problem (http://en.wikipedia.org/wiki/Dangling_else http://en.wikipedia.org/wiki/Dangling_else), anyone? It seems disingenuous to complain about mismatched parens in Lisp when those are trivially handled by most decent editors, and the problem is in no way unique to Lisp.
- Locke1689 16y agoPython would argue that if the primary operating factor in readability is block structure and indentation one should simply add block structure and indentation as a mandatory part of the language and then remove cruft which is no longer necessary.
- DrJokepu 16y agoI don't know about that. Say what you want about Emacs (personally I'm not a huge fan) it does a pretty good job at syntax highlighting and auto-formatting Lisp source. I never had problems with reading well-written Lisp code in Emacs.
- deleted 16y ago[deleted]
- comex 16y ago> Python on the other hand has no macros and doesn't give you much to write concise, abstract, elegant code. There's a lot of repetition and many times it's downright verbose. But where Lisp is nice to write and hard to read, Python makes the opposite tradeoff. It's easy to read. You can determine how to interpret something—a string, a list, a function call, a definition—just by looking at the code locally. This is a great quote. If you replace Python with C and Lisp with C++, it's exactly what I've been trying to articulate (as a C fan) for some time now. In fact, I think it's much more applicable to C than to Python...
- neutronicus 16y agoIt's easy to read. You can determine how to interpret something—a string, a list, a function call, a definition—just by looking at the code locally. I actually find that Lisp scores some local-readability points over Python in a few cases, mainly because Lisp is more explicit about scope, e.g. (let ((a (something)) (b (other-thing)) (frobnicate a b)) ...other code versus a = something() b = other_thing() frobnicate(a, b) ...other code is more explicit about the intended lifetimes and consumers of the data "a" and "b". Lisp also has the "with a = (blah)" keyword for "loop" so the assignment can be made specifically in the context of loop preparation. All in all I'm actually happier with my ability to signal my intent (and gauge other programmers' intent) in Lisp than I am in Python.
- Locke1689 16y agoPython is explicit about scope by using the same indentation block. I can glance at python code and immediately tell what the scope is because it's in the same indentation block (removing for the moment things like the global keyword, which tend not to be a problem in practice).
- neutronicus 16y agoCan you increase indentation arbitrarily, though? Like, say I want to initialize some data for a loop, that I wouldn't need later, could I: main_scope_stuff() c = create_context() for foo in foos: do_something(foo, c) do_other_thing(foo, c) accumulate(foos, c) more_main_scope_stuff() to emphasize that c was only important to the loop and the call to "accumulate"?
- Locke1689 16y agoOf course it's possible to increase indentation arbitrarily: simply create a new function. Any programmer should know that too many immediate levels of lexical context is bound to confuse the reader anyway. I'm not really sure what you're trying to show with that code, though. Is your objection that every do_ function is requiring a context? Edit: I see what the parent was saying now, see bottom comment. Also, see StavrosK's comment if you're fine using Python 2.5 (released 2006).
- lispm 16y ago(f x) is not different things. It is just that the meaning of (f x) depends on a context and is only meaningful in a context. (f x) alone is a call, a macro or function. (let ((f x)) ...) , here (f x) is an item in a binding list. What a Lisp programmer sees is a pattern introduced by LET: LET ((var value)*) body There are a handful of basic macro code structure patterns. Once they are learned and attached to the symbol of the corresponding macro, the understanding of code is much improved. Reading Lisp code requires to identify the visual marker - the symbol in front. Depending on that there are code patterns that can be visually destructured: lists, property lists, assoc lists, lambda lists, binding lists, ... In other languages the visual markers are supported by different characters. In Lisp it is a symbol. { a := b + x; } vs. (progn (setq a (+ b x))) As a Lisp programmer I'm trained to see the PROGN, not the parentheses. It is a bit like being afraid of riding a bicycle for the first time. How can one move forward and balance at the same time? Difficult. Once learned it is simple and hard to unlearn. How can one read the various Lisp code patterns? Once you have learned them it is easy and hard to unlearn.
- Someone 16y agoIf that argument is valid, why not go a step further to, say, early basic implementations? Back in the day, there was no discussion possible whether 'x' was an integer, float, or string. If it were a string, it would be x$, if it were an integer, i%. I do not think his argument is valid. In both languages, once a program is large enough for any syntactic ambiguity to make a difference, there will be more than enough semantic clues to help solve the syntactic disambiguaties. In other words: yes, one can write really hard to understand Lisp, where (f x) has six meanings in one line, but outside of obfuscated code contests, programmers just do not write such code. Edit: the semantic clues I refer to are those implied by function names, names of data types, etc.
- deleted 16y ago[deleted]
- jhuni 16y agoLisp seems to be optimized for writing code; Python seems to be optimized for reading it. You know what is truly optimized for writing code and not reading it? Mathematical notation - and for good reason, most mathematical equations are written on paper. Mathematicians use one letter variable names like (i, j, n, m, x, y, z), various Greek letters, infix notation, and other things that often makes mathematical equations incredibly hard to read, but easier to jot down on paper. Almost all programming languages, such as C, Java, Python, and Perl are influenced by this notation that although it was easy to write on paper, is not as easy to read and not nearly as easy to parse. Lisp is not nearly as easy to write on paper - and it often is harder to type - however - for any experienced Lisper it is the most readable programming language there is, hands down, because once you use it for long enough the parenthesis fade away and you can write/read code without the mental overhead that is entailed by parsing.