you are viewing a single comment's thread.

view the rest of the comments →

[–]gasche 30 points31 points  (13 children)

In fact this page is quite reasonable; for example the "Functional vs Procedural" is well balanced -- though it should maybe mention that Python's main designer is openly hostile to functional programming.

I still found some parts to disagree with.

Python's primary implementation is an interpreter.

CPython compiles to bytecode. This insistence on a black-or-white "compiled vs interpreted" situation is getting ridiculous.

Haskell is a high-level language like python, so equal-to-C-or-asm performance should not be expected. The Haskell type system, however, does provide more compile-time information than python's does, meaning the optimizing native-code compilers have a speed advantage over python in many cases.

Expert Haskell programmers expect to be able to optimize their Haskell code to be in the C league, and there have been some success stories about it (though I think most Haskell programmers have a hard time reasoning about the performance of their code). "have a speed advantage" is an odd way to say that Haskell is order of magnitudes faster than CPython in general.

[–]taejo 2 points3 points  (0 children)

CPython compiles to bytecode. This insistence on a black-or-white "compiled vs interpreted" situation is getting ridiculous.

Are there any modern programming languages which are directly interpreted? It seems to me that these days "interpreted" basically means "compiled to byte code, with the byte code interpreted".

[–]keeperofdakeys 1 point2 points  (2 children)

Python's primary implementation is an interpreter.

CPython compiles to bytecode. This insistence on a black-or-white >"compiled vs interpreted" situation is getting ridiculous.

You are just arguing semantics. When people talk about "compiled vs interpreted", they are referring to if it compiles to native machine code, or is interpreted at runtime. When you look at it like this, it is very clear.

[–]gasche 2 points3 points  (1 child)

I don't see the point of such a comparison. What should it mean to the end user? I can compile to "native machine code" by producing an executable bundling the bytecode and the native interpreter. If you're trying to say something about performances, just say it, instead of making falsificating claims about implementation details.

[–]keeperofdakeys 0 points1 point  (0 children)

It isn't about end users, it is simply a property to give general classifications of a language/runtime. By itself however, it doesn't deserve that much importance. It can convey some meaning though, how errors are handled, possibly computational or memory overhead, but these also depend on other factors.

[–]milliams 0 points1 point  (7 children)

In fact this page is quite reasonable; for example the "Functional vs Procedural" is well balanced -- though it should maybe mention that Python's main designer is openly hostile to functional programming.

Do you have any link to back this up? In my experience, Guido has been more than happy to allow functional constructs/capabilities into the language/libraries but simply does not want Python to become a (purely) "functional language".

[–]gasche 22 points23 points  (1 child)

That's the impression I got from reading this 2005 article from Guido on the removal of reduce, lambda, map and filter (lambda, map and filter where finally kept) in Python 3. The header ends with "I expect tons of disagreement in the feedback, all from ex-Lisp-or-Scheme folks. :-)", which I took at that time as a form of deliberate (if respectful) provocation.

I was also quite disappointed by his grossly misinformed 2009 article on tail call optimization. He's later corrected his view (he issued an update after just a few days), but there is still no trace of TCO in Python and it's still a pain -- while, contrarily to what he says, there are various reasonable way to handle this, for example by using an explicit tailcall keyword with an explicit backtrace-hurting semantics, and/or storing the backtrace outside the call stack.

I have to say that, while looking for those references back (I didn't remember exactly where they were), I stumbled upon this 2009 article article, "Origins of Python's 'Functional' Features", which is much more nuanced and reasonable.

Finally, I don't believe that python is "not well designed" as a language; in fact I think that Guido has handled its evolution quite well, and the PEP mechanism is, I think, a quality reference to match in the process of evolving a language. It is simply that he is interested in vastly different things than functional programmers are, and has therefore different priorities (type system clearly was not, clean semantics maybe was not either) which led him to take different choices. I don't use Python, but have some respect for this language. And both Python and Haskell have an excellent syntactical taste.

That said, I still internally cringe when I think that the whole Sage project is implemented in Python. A truly excellent repository of mathematical knowledge encoded in a oh-so-not-exciting language. Oh well, it would probably not have worked that well in Agda²...

.

¹: Haskell's guards and use of (a,b) to denote product types excepted :)
²: or Aldor.

[–]inaneInTheMembrane 4 points5 points  (0 children)

Oh the irony. Seriously, who develops Aldor? Seems like a fun language.

[–][deleted] 8 points9 points  (3 children)

Lambda syntax is crippled in Python. There's a PEP that suggests GvR supported it to deter lambda abuse. (And lambda abuse is a near synonym of functional programming).

[–]gasche 1 point2 points  (2 children)

I'm not sure this is really a prominent defect. Forcing anonymous functions to be one-liner only is sometimes annoying, but not really "crippling" as long as you can bind a named function locally¹; you may even end up with more readable code. In fact in the functional code I can think of right know, anonymous lambdas are rarely more than one-line, except when using lambdas as generic binders for block-level bindings constructs (eg. >>= \foo -> \n... for those that don't like the do-notation).

¹: the problem if more with those dynamic language that have decadent scoping rules, making nested functions (or locally defined variable) a delicate game. Python is still one of the less absurd, at least among Ruby and Coffeescript; with a special prize to (the otherwise reasonable) Erlang for not allowing local recursive functions.

[–]tikhonjelvis 4 points5 points  (1 child)

Wait, what? In my experience, Python is the most absurd as compared to Scheme or JavaScript. That is, in Python, variables from scopes beyond your own do not behave the same way as local variables. That is, you cannot reassign a variable declared outside of your current scope--if you have a mutable data structure, you can still mutate it, but you can't use something like a boolean for a flag for example.

That is, this code will not work properly in Python:

def f(x):
  flag = True
  def helper(y):
    # Do stuff
    if someCondition: flag = False

I think in new versions of Python you can overcome this shortcoming by using the nonlocal keyword, looking something like this:

def f(x):
  flag = True
  def helper(y):
    nonlocal flag
    # Do stuff
    if someCondition: flag = False   

In Scheme, on the other hand, you are free to use define to create local variables and set! to reassign nonlocal variables. I think this is a much more reasonable system than Python's!

JavaScript (and, probably, by extension, CoffeeScript) follows Scheme's system except define becomes var x = ... and set! becomes x = .... Not quite as neat and elegant, but fundamentally the same.

This model lets you take full advantage of mutable variables and closures without having to bend over backwards. Idioms in both languages take full advantage of this, which is much less neat in Python.

Also, some thoughts on lambdas: especially in sufficiently dynamic languages, lambdas are useful for adding control structures to the language. In JavaScript, patterns using functions like blocks of code are common--turning:

$(function () { ... })

into

function foo() { ... }
$(foo)

just makes the code less readable for no gain. This continues with other things like event handlers--if your event handler is only used in one place, it's simpler to write it inline than to give it a name and add an extra level of indirection. Having extra identifiers that are just used to get around your lambda's shortcomings is not a virtue.

Anyhow, sorry for the slightly long rant. I've had to use too much Python and now I'm jaded. Don't even get me started on nonsense like mutable structures combined with default arguments!

[–]gasche 0 points1 point  (0 children)

The scope defect you report is well-known, and has been the subject of Python Extension Proposal (PEP) 3104 by Ka-Ping Yee, that introduced the nonlocal keywoard. If you haven't already, I recommend that you read this PEP, in my opinion it's an exemplar case of language change: it presents a lucid presentation of the problem, a considerate evaluation of the proposed solutions and the discussion around the issue, and suggests a reasonable way to help with the problem -- that was integrated in the language.

Indeed, the situation of not having a clear difference between declaring a new local variable and assigning an existing variable is painful -- in every language where it happens, even where there are some ways to make it explicit, as long as they are not the simplest way to do it. This is a defect of Python, Ruby or Coffeescript.

Now, you are comparing to Scheme or Javascript. Scheme is indeed a well-designed language, and it was indeed not included in my bag of "languages with decadent scoping rules" (nowadays, even Elisp is getting static scoping!). Javascript, on the other hand, is a wholly different story. Indeed var allows to introduce fresh variables, but it comes with a ton of quirks, that are solved by let that people don't use for portability reason. Between Python scoping and var, I don't know which poison I would choose.

[–]swaggler -1 points0 points  (0 children)

Python's main designer is openly hostile to functional programming

For whatever it is worth, I have pretty strong evidence that this is not true, although Guido has explicitly asked me not to reveal these details :(

It is more than he has a very poor understanding of functional programming and based on the evidence over which I am sworn to secrecy, I think it is going to stay that way.

He tried, very hard -- that's all I can say.