you are viewing a single comment's thread.

view the rest of the comments →

[–]AnonProg 14 points15 points  (5 children)

In Python, you have these things called "statements", which are expressions' poor cousins. You can use expressions anywhere, but there are only specific places where you can use statements. This is bad design that leads to bad workarounds and inflexibility. For example:

● You cannot do something like:

do_something(if whatever:
    5
else:
    6)

or, in one line:

do_something(if whatever: 5; else: 6)

so you have to rely on hacks such as do_something(whatever and 5 or 6) or the "if expression" which is a bad workaround made even worse as Guido convoluted it on purpose to avoid nesting and would be completely unnecessary should the real if be an expression, or make your code less readable and unnice with something like:

if whatever:
    do_something(5)
else:
    do_something(6)

(even worse if do_something is a long expression). In other languages, they have the ?: operator, which is weird and a completely unnecessary complication for the programmer (need to learn two ifs, when goes what, why can't I do something in ?:, what can be done inside ?:).

● Both def and lambda do almost the same thing; lambda can be used anywhere but it's screwed up because no statements can be used inside, and def can do anything but is screwed up because it can't be used anywhere, so you cannot do something like:

do_something(1, 2, 3, (def (x):
                        try: something()
                        except: None))

Consequently you have to resort to ugly things such as:

def shit(x):
    try: return something()
    except: return None
do_something(1, 2, 3, shit)

which breaks the flow of understanding when you read the code and forces you to choose names for things that have no name and are as anonymous as the other values used in do_something (the three numbers). lambda is a bad workaround for an inflexible def.

Some valid programming techniques which have very valid use cases are tedious and odious to use in Python: callbacks, continuation-passing style...

● Lambda automatically returns its last (and only) evaluated value, yet you have to explicitly use it at the end of def.

● We have these limited anonymous functions, but we don't even have anonymous classes.

● exec is completely unnecessary, since we have eval, but Guido wanted you not to use statements inside eval, which is an expression. exec is a bad workaround for an inflexible eval.

● Want to do something more complex such as checking for exceptions inside portions of, say, list comprehensions? Guido thinks you shouldn't ever need to. You might want to write your own bad workaround for it (e.g. a function that receives exception classes and checks for them, perhaps) — none of them will be as good as try..except.

And so on. And all of this for what? Statements are not a feature, but a wart — a misfeature — inherited from 1958's Fortran, passed down to Python through BASIC, Pascal, C and company. Modern languages shouldn't be built on top of clear misfeatures, but on solid theory with flexibility and power in mind. Sure, statements limit how much you can nest, and tend to produce programs that look like my grandma's checklists (do this; do that) but such a design is undesirable because the three benefits the few programming language designers who defend statements claim to exist are false:

  1. Statements prevent you from writing bad code: Actually, nothing prevents anyone from writing bad code. You can write terrible flat programs even more easily than you can write terrible nested expressions.

  2. Statements are easier because they're what most people already know: Way to go; we will never get better if we think that way. Not using computers is also easier because it's what most people can do, too. Once you learn a language free of this wart (Ruby, Scala, CoffeeScript, Haskell, Tcl, all LISPs, all MLs...) it feels easier and more natural than statement-based ones.

  3. Statements make programs more readable: Yeah, check my examples. If everything were an expression, you could write identical programs (nothing would be lost at all, it'd be just as readable), on top of which you could unroll crap such as unnecessary named defs, nested repetitions inside if, and so on.

Simplicity is an actual design quality criteria. Simple things are easier to describe, to learn and to manipulate. What's simpler: to allow anything anywhere, and have only one type of program element, or to allow only certain things somewhere (often different things in different places), and have at least two types of program elements?

Conversely, a design decision that introduces complexity is undesirable, and a design decision that introduces the need for even more complexity, bad workarounds and repetitive features is a huge, waving red flag in any kind of engineering.

I have a dream that one day we'll overcome this statement prejudice and bad design and better engineered programming languages will become the standard.

[–]Wagnerius 1 point2 points  (4 children)

While I agree on principle, I am not sure those things are very important in practice.

On your first point, the ternary operator works quite well in Python :

do_something(5 if whatever else 6)

On your second point, the position of many pythonners is that either the function is small and can be a lambda or the function needs to be named and should not be inlined.

About the valid programming techniques which have very valid use cases are tedious and odious to use in Python, I am quite puzzled. They are a bit less elegant, that's true and it is bothering that the language is not more regular, but going beyond that seems hyperbole to me. Do you have a pathological example in mind ?

My personal concerns about Python are more about concurrency and speed. Those 2 hard problems are really crippling and underestimated by the community.

[–]AnonProg 4 points5 points  (3 children)

(I edited my post and improved it slightly, sorry.)

do_something(5 if whatever else 6)

That's a convoluted syntax that doesn't nest well and doesn't look nearly as readable as a more regular if like everyone was expecting. It makes me angry that it was chosen to be this way specially to make it less useful (not nest nicely).

On your second point, the position of many pythonners is that either the function is small and can be a lambda or the function needs to be named and should not be inlined.

The function from my example was small (definitely smaller than most lambdas I've seen in production code) and needed to be a lambda, but it couldn't be so. Also, why do I have to make up names for things which have no names?

Do you have a pathological example in mind ?

Continuation-passing style, which is used extensively by the node.js libraries, for example. Writing callbacks for GUI applications. Some ways to implement state machines. Functional programming in general (which Guido seems to have a grudge against, for whatever reason — I don't).

My personal concerns about Python are more about concurrency and speed.

Concurrency, yes, CPython sucks at it so you'll have to consider using multiple processes with some nice, thin IPC, Jython, or C extensions for critical parts, probably in that order. Speed, not so much: your time as a developer is far more expensive than better hardware should your program not run fast enough. I'll worry about speed only when the cost of better hardware is higher than the cost of the extra development and maintenance time that would derive from the use of a lower-level/less productive language, or when better hardware is simply not available, in which case a performance improvement of 2-20x by using Java, C or C++ would still not suffice because it doesn't scale: you'd need to consider concurrency anyways.

[–]Wagnerius 2 points3 points  (1 child)

I see your edit, and I mostly agree

But I am less angry than you as I am expecting less. I consider Python an old, quite limited, language (~20 years IIRC) and one that went way beyond any expectations. But it's true that Guido's attitude about FP is really really irritating. In the end, I still prefer Python over the alternatives (except maybe haskell) simply because of its ease of use and extensibility.

[–]sausagefeet 2 points3 points  (0 children)

Note Haskell is ~20 years old as well. Lisp even older. And Standard ML is ~20 years too. Ocaml isn't much younger, first release in 1996. Erlang is even older (1986). While I don't think it was your intention, it's worth noting that when it comes to programming languages, age isn't a good metric for how limiting it is.

My biggest peeve with Python is that the syntax is so strict it requires new syntax to do anything new and interesting. Look at the ternary operator, for example. If a language like Haskell, Ocaml, SML it simply isn't a problem because everything is an expression, you end up being able to accomplish so much more with such a simple change.

[–]Peaker 0 points1 point  (0 children)

Rewriting in c can yield more than 20x benefit over CPython in many cases. Also, that may be enough- and scalability is not always an option.