5 ms·
"Kicking and screaming", to be fair, is a bit of a literary exaggeration. But Rossum did not particularly want to add functional features to the language and on
by tikhonj 11y ago
"Kicking and screaming", to be fair, is a bit of a literary exaggeration. But Rossum did not particularly want to add functional features to the language and only did so at the behest of his users. Lambda as well as map/filter/reduce were "a significant, early chunk of contributed code", not something he intended the language to have from the outset[1]. More recently, he has been trying to deemphasize these features in favor of list comprehensions.
Moreover, Rossum is opposed to proper tail calls and even recursion in general[2]. He also doesn't like folds, and generally thinks you should just express that sort of logic as some sort of loop. (I forget exactly where I read that opinion, but it could easily have been [1].)
He's a staunchly imperative programmer, and the design of Python shows this off consistently except for an initial accident of first-class functions and closures (of a sort)—a design he likes because it enabled other, non-functional language features like new-style classes.
"Kicking and screaming" might have been an exaggeration, but it captures his overall attitude towards functional programming pretty well.
[1]: http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html http://python-history.blogspot.com/2009/04/origins-of-python...
[2]: http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html http://neopythonic.blogspot.com/2009/04/tail-recursion-elimi...
- setheron 11y agoI just can't understand anyone who is black and white. I like when I have both tools at my disposal: recursion and iteration.
- hueving 11y agowhen you have a project concerned with readability, adding new features is a huge community cost in the long run because it's one more thing you have to learn to deal with as you go across projects. One of the wonderful things with python is that you can dig into the code of most python projects and not have to worry much about completely different idioms requiring a complete context switch to understand how they work. He is not really being black and white, he is doing a service by preventing language bloat ala C++ as much as possible.
- mhd 11y agoIt always struck me as a reaction against Perl's "Tim Toady" approach, encouraging a more idiomatic and unified programming strategy to ease comprehension and teaching (IIRC the origin of Python, or at least ABC).
- sklogic 11y agoThis is exactly what makes Python a bad language. Lack of expressive power results in an unnecessary complexity of the code. It's much easier to comprehend a short, compact code written in the familiar, domain-specific idioms rather than digging through convoluted pile of low-level leaky idioms like loops, list comprehensions, generators, classes, recursion and all that irrelevant crap.
- afc 11y agoJust wanted to add my voice: this matches exactly my perception. I used to really like Python, but I've come to the conclusion that there's a certain point in terms of the complexity of a Python program where everything just blows up and it's next to impossible to keep it from becoming a tangled mess. This point is reached incredibly soon, something like five classes with some inheritance, some interface/virtual/abstract class. Ugh. Now I avoid Python as much as possible, much preferring C++ or Java, which I think work incredibly better for larger programs.
- kyllo 11y agoI used to think I needed both, but since picking up Haskell I don't miss for loops at all and I rarely need to use explicit recursion either--now I almost exclusively use higher-order functions like `map`.
- Retra 11y agoWhen I started learning Python, I always used map and filter because they were just how I thought about problems. But there is a certain bit of elegance to being able to write [process(child) for child in node if child is not None] in lieu of map(process, filter(notNone, child)) The functional style makes better use of conceptual primitives, but the imperative style is generally better for documenting. for child in node: if child is not none: # Comment explaining decision. process(child) # Comment explaining more stuff.
- gnud 11y agoI think LINQ got this very nearly right. You can write this LINQ-style from child in node where child != null select process(child) or with extension methods node.Where(c => c != null).Select(process)
- foobarian 11y agoI'm actually a bit scared of using recursion in production (at a web company). It has its place of course, but gratuitous recursive code that could have been written without gives me pause. It's too easy to miss an edge case and end up with a stack overflow, and that can bring down a whole server farm.
- rhaps0dy 11y agoThe first thing you show is a list comprehension [1], and it's still very much functional style, even if it has a "for" in it. Heck, Haskell has pure list comprehensions. [2] [1] https://en.wikipedia.org/wiki/List_comprehension#Python https://en.wikipedia.org/wiki/List_comprehension#Python [2] https://en.wikipedia.org/wiki/List_comprehension#Haskell https://en.wikipedia.org/wiki/List_comprehension#Haskell
- dalke 11y agoThere are many thing he didn't intend from the outset, so that by itself isn't so significant. Some other things he didn't intend were the type/class dichotomy and the inability to raise an exception from comparison. Two changes that come from external users include David Ascher's rich comparisons and Samuele Pedroni's proposal to use the C3 method resolution order. Van Rossum's preference for loops over map dates to at least 1994, which you can see in http://legacy.python.org/search/hypermail/python-1994q2/0705.html http://legacy.python.org/search/hypermail/python-1994q2/0705... : > "Steven Majewski might not agree with me, but in Python you are better off using "for" loops (the overhead of calling a function for each element is quite substantial)." You can see that's still true with CPython: % python -mtimeit -c 'x=range(100)' 'd=[]' 'for a in x: d.append(a*a)' 10000 loops, best of 3: 22.1 usec per loop % python -mtimeit -c 'x=range(100)' 'map(lambda a: a*a, x)' 100000 loops, best of 3: 18.2 usec per loop % python -mtimeit -c 'x=range(100)' 'd=[];ADD=d.append' 'for a in x: ADD(a*a)' 100000 loops, best of 3: 12.7 usec per loop % python -mtimeit -c 'x=range(100)' '[a*a for a in x]' 100000 loops, best of 3: 9.91 usec per loop FWIW, Python has made at least one language change in order to improve performance. In Python 1.x the following was possible: def f(x): from math import * return cos(x*sin(x)) Python 1 used a dictionary for locals, while Python 2 introduced a pre-allocated array of variables for locals so lookup could be done via a simple index offset. In the same email, van Rossum writes: > "To be honest, I wish I hadn't introduced lambda, map, filter and reduce -- they support a style that is inconsistent with the rest of Python. Unfortunately, in the sake of backward compatibility, I can't take them out. So enjoy them if you have to. But don't get too thrilled!" That same email also says: > Ah, the infamous "first class objects" argument again. Really, I don't understand all the fuzz about lambda, and I don't see why its introduction made functions any more first class than they already were in Python. They are entirely syntactic sugar for local function definitions. Everything you can do with lambda you could always do with local functions, at the cost of one local temporary identifier -- surely no big deal! This is interesting because you mentioned "initial accident of first-class functions". Why do you think first-class objects are an "initial accident", and not a deliberate decision?