Hacker News new | ask | show | jobs
by wynand 5651 days ago
Perhaps but I think it depends on who's writing it.

I love Python and haven't touched Java in years but my colleagues who use Java seem to write programs that are maybe around 3 times longer (this is a ballpark figure).

I get the feeling that programmers that produce gobs of Java code are probably going to do the same thing in Python. A good Fortran programmer can write Fortran in any language :).

5 comments

Overly wordy Java coders would still be overly wordy Pythonistas, except the Python culture enforces the "Python is not Java" mentality so they would be corrected on almost every turn, plus the code tutorials and examples from which they learn would be shorter. As a result they would become less verboten very quickly.
>examples from which they learn would be shorter. As a result they would become less verboten very quickly.

I'm definitely going to use this definition of 'verboten' from now on. I like your style. Fuck the dictionary!

To help keep everyone out of a "What is that freaking word? I know it but can't think of it!" loop, the word he meant to use was verbose.

Also, to save you the work:

  ver·bo·ten
  forbidden, as by law; prohibited.
http://dictionary.reference.com/browse/verboten
Also, verboten is a german word possessed of a slightly antagonistic quality when placed in english speech. This is why it amused me so much.
Obviously I meant "verbose" :-p LOL
That and most new-python converts initially don't think in a very functional way. After the "aha" moment of lambda love, the Java ways can be unlearned.
Functional programming is not just about passing function pointers. In this case, C is functional. It's about expressing your code as series of function applications i.e., no mutable state, no side effects, no differences between statements and expressions (everything has a value). Very few languages are purely functional, so it's rather a sliding scale.

Nonetheless, functional programming is not the encourage common style in Python: there are no data structures available, many methods have side effects, it's hard to isolate mutable values from mutable. Not saying it's right or wrong, it's just different.

I should also note that Common Lisp isn't all that functional compared to other languages: I'd rate it being just slightly more functional than Ruby. The reason it appeals to some Lispers is due to simple syntax, data structure literals and dynamic typing. These features are common now, are useful for experimental programming (of the sort that frequently happens in AI and ML work) but they originated with Lisp. Lack of syntax, presence of macros and resulting ease of metalinguistic abstraction are not present in Python, but not every Lisp(er) used them: some preferred functional style (e.g., never using loop macro and using higher order functions and closures as means of abstraction), some preferred macros and DSLs, some stayed away from both.

Java bashing is healthy: while I personally don't mind Java, many developers were forced into writing Java (having previously worked in Smalltalk, Lisp, C++, Perl, and others) as the language was heavily marketed to managers. Java hatred and bashing is thus a well understood reaction (although the culprit for verbosity are awfully horrid libraries such as Spring and J2EE: alternatives like Guice, for example, are much less verbose). However, JVM is now home to Scala, a much stronger candidate for an OO/functional hybrid language than Python (that's not to say Python isn't an elegant and powerful language with many advantages, especially when it comes to tools/automation development).

Frankly I've found python to be quite antagonistic to functional programming with very weak lambdas and poor building blocks for building interfaces in monadic pipeline style. I guess coming from java it would seem refreshing but coming back from haskell or even just javascript it feels like a straitjacket.
I hear this argument a lot, but I don't know these concepts well enough from haskell et al to fully understand it. Could you be more specific about this? Perhaps, provide a direct example?
I think one key thing is that lambdas are second-class citizens in Python in terms of the kinds of code you can express. Python lambdas can only contain one single expression and nothing else. For more complicated functions, in particular any function that requires statements, you are always required to use nested named functions, e.g.

    myList = [[1, 2], [3, 4], [5, 6]]
    for elem in myList:
        del elem[0]
cannot be done using a lambda, as

    map(lambda elem: del elem[0], myList)
results in an error. Until Python 3, that also meant that

    map(lambda elem: print elem, myList)
was also a syntax error because of the print statement. For a more elaborate example, consider the following JavaScript function which returns a function that increments a counter every time its called and returns the value before it was incremented:

    function makeCounter() {
        var value = 0;
        return function() {
            return value ++;
        }
    }
You would use this as follows:

    > c = makeCounter();
    > c();
    0
    > c();
    1
    ... and so forth
There is no way to implement this in Python using lambda; the closest equivalent (assuming Python 3 for the nonlocal keyword) is

    def makeCounter():
        value = 0
        def count():
            nonlocal value
            tmp, value = value, value + 1
            return tmp
        return count
because there's no way to have that assignment take place in a lambda.

Of course, Haskell has neither state nor statements, so the above examples don't literally show why Haskell's lambdas are necessarily superior, but the point isn't that Python disallows assignment in lambdas; it's that Python's lambdas can only express a subset of possible functions, while JavaScript and Haskell (and Scheme &al.) don't have that limitation.

Why not use a list comprehension for that? Like:

  my_list = [[1, 2], [3, 4], [5, 6]]
  my_other_list = [ elem[1:] for elem in my_list ]
You could also reassign the my_list name to your processed list, but changing the state of things (you are not really changing anything here, just calling something different by an already known name) is very un-functional.

As for your second example, I would consider using "yield".

Excellent explanation. I think most people's issue with python's lambda is that it isn't what they expect. There are generally some gotchas and the syntax diverges from that of a regular function.

I side step the lack of closures by using named locals with the keyword arguments when defining inner functions. However, for numeric types, this doesn't really work:

    def makeCounter():
        value = 0
        def count(value=value):
            tmp, value = value, value + 1
            return tmp
        return count

    inc = makeCounter()
    print inc()
    print inc()
The above prints '0\n0', but if we use an object that is used "by reference" in a such a function, one can get this behavior:

    def set_adder():
        s = set()
        def add(item, s=s):
            s.add(item)
            return s
        return add

    s = set_adder()
    print s(1)
    print s(2)

    t = set_adder()
    print t(3)
    print t(4)
This will print:

    $ python mk.py  
    set([1])  
    set([1, 2])
    set([3])
    set([3, 4])
Your comment provoked me to try Haskell and see what the fuss is all about. I came across this fun little Try Haskell thing (yeah, copycat of TryRuby) http://tryhaskell.org/ It's very interactive and fun.

I think basically what the parent comment is saying is that it's much easier to pass functions as arguments to other functions in Haskell than it is in python. They call them high order functions.

I quite agree with you (especially after writing a lot of javascript) - it's funny you mentioned javascript as I said the same thing in a child comment I made below :-)
So, I have been working at learning Python (I do Java at my day job). Where can one pick up this "lambda love" quickly? Any links or pointers?
In the past, I would've said read The Little Schemer book for better understanding recursion and lambda (basically, a lambda function is an anonymous function - meaning you don't have to name it). JavaScript is actually a great language to better understand functional programming - it really is Scheme in C-like syntax. Here's a great little chapter on functional programming in javascript (http://eloquentjavascript.net/chapter6.html). Just bear with me and read it - it's extremely worth the trouble. You'll understand the syntax fine even if you don't know javascript.

After you read that, hopefully you'll start passing around functions as arguments inside another functions. It's tremendously fun and changes your way of thinking about code.

And this little answer in StackOverFlow summarizes what lambdas can do and how you can use it in python: http://stackoverflow.com/questions/890128/python-lambda-why/...

The simplest explanation is think of your program functions like mathematical functions that spit out values, with that in mind you can start sending in functions as arguments. A very brief e.g from the link:

def addition(n): return lambda x: x + n f = addition(3) f(4) # is 7

here, f is actually binded to a function - the addition function from above (because it returned a function called lambda).

You seem to be conflating the idea of closures and functional programming. Functional programming is more about avoiding state and side-effects, which is antithetical to most Python and JavaScript code. A lot of languages, including C, support the kind of programming you're describing, but that's not "functional" per se.

http://en.wikipedia.org/wiki/Functional_programming

You can't get much better than Norvig. Here's one possible starting place: http://aima.cs.berkeley.edu/python/readme.html
I've worked on such huge Java programs being maintained and updated for over 5 years. I actually don't think it is Java as a language which helps in maintenance. Type checking by the compiler does help, but in reality you have Spring, Hibernate, JSF, JSP,.. where compile time checking doesn't apply anyway.

In my opinion there are 3 things that help with maintenance: * automated tests (to see what breaks if you change something) * refactoring tools (helps in keeping code clean) * domain driven design (helps in mapping a business concept to a piece of code)

These are all things you could do in Python as well.

Isn't refactoring much harder without static typing ?
I believe one of the first refactoring was for Smalltalk, so it's not impossible. These days you also have IDEs with basic refactoring support for Python, Ruby, Javascript, Actionscript,.. from JetBrains.
I feel like a lot of the languages meant to be written with an IDE end up being longer in terms of total LOC, but a pretty big chunk of that is all auto-generated noise.
> Perhaps but I think it depends on who's writing it.

Inexperienced programmers write sub-optimal (or plain weird) code. Once they learn their tools, they will write better code. That's not surprising at all.

That's basically my opinion too.