
PEP 308 and why I still hate Python - dvt
http://dvt.name/2017/03/10/pep-308-and-why-i-still-hate-python/
======
stcredzero
_To be fair, Python isn’t terrible, but throughout its lifetime, it made some
incredibly poor design decisions_

Substitute {{x}} for Python and you have a template for a Hitchhiker's Guide
entry for just about every programming language, ever.

~~~
oxryly1
Yup. And Python is certainly one of Stroustrup's two kinds of languages:

"There are only two kinds of languages: the ones people complain about and the
ones nobody uses." \- Bjarne Stroustrup

~~~
cat199
but lisp...

(occasional lisper)

~~~
oxryly1
Yes lisp.

(constant lisper)

------
Animats
Python is an imperative language. The control structure, based on indentation,
is well matched to Python's imperative character. Attempts to retrofit a
functional style to Python fit Python's syntax badly. Lambdas, conditionals,
and list comprehensions look painful if they extend beyond one line, because
the indentation assumptions of Python just don't fit.

As a practical matter, only use Python's functional features in one-liners.

~~~
userbinator
_Python is an imperative language._

...as are many others with the conditional operator's operands in the normal
(condition, true-case, false-case) order:

[https://en.wikipedia.org/wiki/%3F](https://en.wikipedia.org/wiki/%3F):

I think being "functional" or otherwise has nothing to do with it. Even in
imperative languages you must use expressions, and it is there that the
conditional operator is most useful.

~~~
pjvandehaar
[https://en.wikipedia.org/wiki/%3F%3A](https://en.wikipedia.org/wiki/%3F%3A)

------
tzs
I'm not sure why the author calls the two branches of in if/else the
consequence and the final_consequence. That naming suggests that you do both
of them, with the latter coming after the first, which is of course not how an
if/else works.

I'm sure that nearly everyone reading the article knows how an if/else works,
so that naming won't actually lead them astray, but it just feels ugly.

~~~
dvt
Bad wording on my part, point taken.

------
derefr
So, Ruby has:

    
    
        consequent-expr if antecedent-expr
    

...which has all the same problems as the PEP308 example, as far as I can
tell. Its (implicit) else-clause is just always nil.

I can't tell from the author's argument whether this condemns Ruby as well, or
if something about the PEP308 style was uniquely bad.

I could see something definitely worse about the readability of this code:

    
    
        {long expr} if x else {another long expr}
    

but the author didn't discuss that case.

~~~
Lazare
The difference between Ruby and Python here is that Ruby has a perfectly
functional ternary operator that works as one would expect. It _also_ allows
some other crazy syntax which can be appropriate in some cases, but it doesn't
force you to use it in all cases.

Python _does_ force you to use their awkward conditional expressions; there is
no normal ternary operator.

There's a big difference between a language which _lets_ you write hideous
code, and a language which _forces_ you to write hideous code.

~~~
TheDong
Python does not force you to.

In any case where you can use PEP 308, you can use a boring traditional "if
else".

~~~
Lazare
Is that intended as a _defense_ of Python's ability to enable clear, concise,
expressive code? :)

More seriously: Yes, you are obviously correct. But while you can use if/else,
you can't use a ternary, and you can in Ruby. That's why people complain about
the lack in Python but don't wrote the same article about Ruby.

~~~
luord
"Clear, concise, expressive code" isn't something that applies to ternary
operators. They were always meant as shortcuts and, as such, will never be as
clear as if else statements, practically by design.

Though I don't really dislike Python's approach so what do I know.

~~~
jolux
You can definitely use too many ternary operators, but I think when used
sparingly they can be clear and tasteful. As long as you don't start nesting
them or repeating them one after the other you should be fine.

------
rbanffy
Reading it as "Alice studies all night if she goes to the library; if not,
she'll sleep all night" seems perfectly natural.

Having said that, I often use the "else" as a "this should never happen"
clause that raises an error.

~~~
dvt
I agree that it reads naturally, but when dealing with those kinds of
sentences, they always need to be put into conditional form (A->B). Even when
reading text the order of those words matters. Consider:

"I'm going to die ... (gasp) ... if you don't grab me some Subway. I'm
starving"

The sentence is funny because the apodosis is misleading. Even thought that
might be a valid narrative approach when writing a comedy, I don't think it's
an appropriate coding one.

~~~
rbanffy
> The sentence is funny

Code should have literary value. ;-)

------
ezrast
As a fellow member of the hates-Python-but-not-enough-to-quit-my-job-over-it
club, comprehensions are just the worst. Uses variables before defining them,
can't be readably broken over multiple lines, overloads multiple pieces of
syntax, reads inside-to-out instead of left-to-right. Ugh.

~~~
cliffy
What is awful about:

    
    
      foo = [transform(bar) for bar in baz.list() if condition(bar)] ?
    

Seems very readable and expressive. Or are you complaining about how they
execute?

Also \ used judiciously with proper indentation can break statements over
multiple lines without too much pain.

~~~
djsumdog
Yea, I like list comprehensions. I mean they make sense once you're use to
reading the syntax. That's just like the following in Scala:

    
    
       foo = baz.list().filter{ bar => condition(bar) }.map(transform(_)).toList
    

If it's your first time looking at Scala, you'd probably be like, "What the
fuck is that shit?" but as you learn the language, these types of patterns
become common and make a lot of sense.

I mean it's not like weird rules in natural language. At least the grammars
for computer languages are strict, with very few edge cases (compared to
human/spoken language).

~~~
nerdponx
Does Scala have line continuation? I got really used to pipes from R (which I
guess come from F#/Elixir), which in turn got me really comfortable with
multi-line statements like:

    
    
        foo = baz.\
            list().\
            filter{ bar => condition(bar) }.\
            map(transform(_)).\
            toList
    

IMO this is about as readable as it gets. It's like bullet points enumerating
each step in the "algorithm" that produces a `foo`.

AFAIK Javascript also uses this pattern a lot.

~~~
uiri
I think that Scala uses semicolon terminated lines so you would write
something like:

    
    
        foo = baz
            .list()
            .filter{ bar => condition(bar) }
            .map(transform(_))
            .toList;

~~~
djsumdog
Scala doesn't require the semi-colon at the very end, but it does allow for
them if you really want two statements on the same line.

Edit: and yes, that line separation works fine, both compiled and in the REPL.

------
abecedarius
A cute feature of this syntax: in "p if c else q" you can think of "if c else"
as an _infix operator_ like + and the rest. This operator has an algebra
worked out by John McCarthy -- e.g., it's associative. Of course I doubt this
will help the poster to like Python more, but it might amuse others.

------
SFJulie
GvR seems to make readability a priority.

But my problem with

    
    
        true if cond else false
    

is it makes impossible to chain fast choices.

I thought it was a bug, then I understood it was a feature (after talking to
him).

GvR hate ternary operators, the python 3nary is midfix, it sux, but it removes
the possibility for people to do long chained if/then/else in _unreadable
ways_.

If you think I am right and it sux, understand I think forbidding this kind of
operator is like hating shortcuts and goto.

Since I love shortcuts, goto and chained ift and python, I logically found
ways to not care of PEP308 because it is a non problem.

Dispatch tables, and/or used wisely ... there are a lot of ways to not care
about PEP308.

~~~
dvt
> GvR seems to make readability a priority.

And my point is that going against the standard (for over 100 years) way of
reading conditionals is quite the opposite.

~~~
SFJulie
I do agree, and for me it is ok to disagree with GvR.

I would have prefered a ?: but I can replace it with

    
    
         # requires non null default else there is a bug 
         value = arg is MARKER and default or arg
    

So ... I don't bother

------
oxryly1
Why didn't Python do this:

    
    
      x = if condition a else b
    
    ?

~~~
scoppini
I think it could be ambiguous in certain situations. Let's say I wanted to
conditionally set a variable to one of two negative constants. In the current
syntax, that would look like:

    
    
      x = -1 if y else -2
    

However, with your syntax, it would look like:

    
    
      x = if y -1 else -2
    

Which could be possibly confused with trying to subtract 1 from y.

~~~
oxryly1
Ah, and Python uses whitespace and colons to disambiguate, which would ruin
the efficiency of this form.

------
gorthol
I've been doing Python professionally for 13 years (among other languages, but
Python is in the one I've used more). I like the language but I also hate some
things (mainly, the GIL, the lack of static typing now lessened thanks to mypy
and the slowness), but I never tough of the ternary if as evil or found a
single instance where it confused me.

------
joshbaptiste
I rarely see PEP 308 in code bases

------
PaulHoule
Which language do you like?

~~~
dvt
I like Java, Javascript, Go (which holds a special place in my heart), and C++
even. And I'm being a bit hyperbolic -- I don't _hate_ Python, but sometimes I
feel that the language works against you, and not with you.

~~~
deathanatos
You like _JavaScript_ , the language where parenthesizing an expression can
change the value of that expression[1]:

    
    
       > {} + []
      <- 0
       > ({} + [])
      <- "[object Object]"
    

or how the identity x|0 == x doesn't hold for all "integers"[2]:

    
    
       > 4294967296 | 0
      <- 0
    

or how function definitions aren't grammatically statements, making this[3]:

    
    
      function foo() {
        function bar() {} // legal
        if(1) {
           function baz() {} // illegal!
        }
      }
    

this just always bites me:

    
    
       > "a string" instanceof String
      <- false
    

(but seriously, I don't understand why JavaScript needed the object/primitive
distinction. I get it for Java, but not in JS.)

> _sometimes I feel that the language works against you, and not with you._

JavaScript is the language where you ask it, "here, I want to know which of
these guns most adequately shoots my foot."

ES6 improves things considerably; in 10 years we'll have good browser support
for basic data structures, like Map and Set.

[1]: I'm joking. Read it first, then return to this footnote. The sleight of
hand is this: the first expression parses as an empty code block, followed by
a unary plus taking an empty list. The second parses as binary addition.
There's also a terrible amount of coercion taking place. This also "means"
that binary addition "isn't" commutative: {}+[] and []+{} evaluate to
different values; the same trickery is involved.

[2]: the binary or operator, |, silently converts the operands to a signed
32bit integer for the duration of the expression. Note that signed 32bit
integer is a type _not available to the JavaScript programmer_ — it only
arises internally! (The only numerical type available is "Number", which is an
IEEE double.)

[3]: the grammar for functions is essentially "list of statements or function
definitions", so function definitions are only valid at the "top level" of a
function.

~~~
dvt
True, JS is a pain in the butt. But I think it's fun: it feels fluid and that
you can do almost "anything" with it (for better or worse). In Python, I feel
that I'm fighting against arbitrary goalposts or that I'm wracking my brain
parsing some logical puzzle (like in the PEP example).

~~~
secstate
Properly spec'd and implemented language structures are the opposite of
logical puzzles. JS is not fluid, it's broken.

------
BuuQu9hu
Python has list comprehensions because maths has set comprehensions.

