Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This is great except for the enforcement of double-quotes around all strings and spaces around slice operators. These two choices contradict the standard Python documentation, most of the standard library, and the behaviour of the interpreter itself.

When the language itself has an established convention, Black should follow that convention, not fight it. These two weird choices just generate needless churn, which is surprising as it seems Black has quite the opposite goal.

It's a shame, because all the other design choices in Black are pretty good!



Colons in slices are implemented to the letter of PEP 8. Your disagreement here probably stems from pycodestyle mistakenly enforcing a different rule (no spaces before colons on if-statements, defs, and so on) in the slice context.

The language itself doesn't have an established standard in terms of string quote usage. If it did, Black would follow it. What repr() does is a weak indicator and how the documentation is written is random, there was not only no enforcement as to which quotes to use, there wasn't even a recommendation. Black standardizes on double quotes since it has clear benefits whereas the other option does not.


I thought of another way to express this that might resonate better.

What I like about the Black philosophy is that it wants to make code style _uninteresting_. People should think about other things, not formatting. That's a great goal. So it seems to me that the best style choice is the most _boring_ choice. The least creative, least novel way. It should try to avoid inventing new formatting algorithms.

What's the most boring way to format a string literal?

The way the language already does it. The way every Python programmer has already seen string literals formatted from the very first day they started typing things into a Python interpreter.

Even if half of us liked single-quotes and half of us liked double-quotes, you can guarantee that every Python programmer on the planet has seen and lived with strings that are formatted the repr() way, including the double-quote fans. You can't guarantee the opposite.

No one could fault you for doing it the repr() way. Blame Guido :) he made that choice decades ago, and everyone has already had to make their peace with it. It's a solved problem. For anyone writing a program that emits Python code, it's the default way to format a string. It's the least assailable option, and that's a good thing.

How does that sit with you?


I’m a Python programmer and I never had the perception that single quotes are more canonical in any capacity. I always felt that single quotes were for degenerates who didn’t realize that single quotes are most commonly used for chars by the broader programming community. ;)


I've seen single quotes for chars vs. double quotes for Strings in Java, but in sh, it's "Strong Quoting with Single Quotes" vs. "Weak Quoting with Double Quotes":

http://www.grymoire.com/Unix/Quote.html#uh-1

"When you need to quote several character at once, you could use several backslashes. This is ugly but works. It is easier to use pairs of quotation marks to indicate the start and end of the characters to be quoted. Inside the single quotes, you can include almost all meta-characters"

So some of us associate single quotes with proper const strings, with no variable expansion, command substitution or other interpreter hanky-panky.


I’ve always thought that double quotes are for degenerates who don’t pay attention to what a standard repr output is for strings.


And I’ve always thought that triple quotes are for degenerates who... no, wait, nvm.


... who can’t write self-explanatory code.


Code only captures the what and the how, comments for any complex routines can capture the why. Obviously overuse is probably a red-flag, but in my experience code alone doesn’t always capture enough context in any sufficiently complex system.

I get your specific comment may be a bit sarcastic, given the ancestry - but I make this one more for younger developers I see that don’t always filter that ;)


You don't have to press Shift as often to type string literals so it's a win, all other things being equal.


I despise people using single quotes even more than people using tabs instead of space, emacs instead of vim or GNU-style indentation instead of... anything sane :D


I used to use single quotes for dictionary keys and other constants, and double quotes for strings intended to be read by human. I read some article about it a considered it a good convention. Now I see it actually isn't a convention. :-) I switched to black just yesterday and overall I like it, still I miss a bit this distinction between single and double quotes.


Slices: My reading of README.md is that Black inserts spaces around the colon, is that right? Almost none of the Python I've seen in 20+ years is written that way. The tutorial and documentation on python.org don't use spaces around the colon, and it is extremely rare in the standard library (out of over 1100 slice expressions that have operands on both sides of a colon, I count 10 that use the extra spaces).

Quotes: We have a difference of opinion over what constitutes an established convention. If the language's own way of displaying strings has been stable for its entire history, I consider that established. A reasonable choice would have been to do what repr() does (single-quotes unless the string contains a literal single-quote) or a simplified version of it (single-quotes always), not the opposite of what the language itself does.

(I wouldn't care so much about this except that I've really wanted a tool like Black for a while and greatly appreciate the philosophy!)


> My reading of README.md is that Black inserts spaces around the colon, is that right?

I can't speak for the readme, but:

    $ cat test.py
    x = [1,2,3]
    print(x[1: 3])

    $ black test.py
    reformatted test.py

    $ cat test.py
    x = [1, 2, 3]
    print(x[1:3])


Oh, I must have misunderstood. Sorry! I take back my issue with the slices, then.


The README confused me, but I think it's saying that it inserts spaces if needed to make it clear that it's a lower-precedence operator. But unlike operators like +, it's not one that inherently requires spaces.

I tried out black and it does the following (the file originally had no spaces):

    x = a + b
    x = m[a:b]
    x = m[a + 1 : b]
    x = m[a:-b]
    x = m[a : 1 - b]
I would personally still write m[a + 1:b], I think, but black's approach is totally defensible. (I guess I would really write m[a+1:b], and black would rightly correct me.)


m[a+1:b] and f(x=y+1) are weird corner cases of Python formatting.

I usually avoid this problem by adding extra parentheses:

  m[(a + 1):b]
  f(x=(y + 1))


Wouldn't being closer imply being used together by the operator? So: 6/2 * 3 = 9 but 6 / 2*3 = 1? In the slice context it seems very obvious the colon has to be slicing, because it can't stand alone to produce an indexable value. But spacing should use this rule, right? [I think this rule was the one used by fortress, the Guy Steele language?]


Yes, that's the rule black is implementing (assuming I'm reading your comment right and understanding its README right...). m[a + 1:b] is in danger of being read as "take the slice 1-to-b, add it to a, index m on that" - even though we know that isn't a well-typed set of operations, the spacing implies that's how it should be read, same as e.g. m[a + 1/b].

Spacings that don't conflict with precedence are m[a+1:b], m[a+1 : b], or m[a + 1 : b]. While the middle one makes precedence obvious, all three are acceptable. black picks the latter, and I think it picks that one because of another rule that it should prefer writing a + 1 instead of a+1.


Double quotes also have drawbacks, visual noise and the doubling of keypresses required on the most common keyboard layouts.


The "visual noise" makes it clearer the me that it surrounds a block of text, so I don't buy this.

Double quotes are also the convention in english to delineate a literal, so I would argue it's more obvious.

I'll grant you keyboard presses though. There's an obvious advantage to single quotes here, but consider why this is the case. To make the use of "apostrophe" more efficient since it appears far more often than a double quote in english. I suppose it's pragmatic to leverage this advantage in code where string quoting is extremely common...

Perhaps double quoting is a bias I've developed writing code, but I suspect it's actually a bias I carried over from reading and writing english and what simply seemed more obvious.

Language design than supports both makes me crazy. Pick one and enforce it!


You can still type single quotes. You have a tool to convert that for you.

The visual noise complaint is interesting. Do you also consider the letter W to be more noisy than the letter V? Should we discourage the use of noisy letters in the alphabet?


A double-quote is more noisy than a single-quote, and W is more noisy than V.

The difference is that " and ' are equally usable options in the context we're talking about. Quotes are very common, so the visual noise adds up when your screen is full of quote marks. Given that they mean the same thing, and one is both harder to type and harder to read, it makes sense to prefer the other.


> Given that they mean the same thing, and one is both harder to type and harder to read, it makes sense to prefer the other.

Nailed it.


A double quote is in no way harder to read. Only on Hacker News.


this seems a bit reductive.


Yes, why www. was dropped, and quotes are used everywhere in most Python code. The triple doubles for doc strings are the worst example, though I have no illusions pep8 will be changed any time soon.


> The visual noise complaint is interesting.

I thought the same. I guess you could just modify your programming font to make the double quotes really tiny :)


I agree about the noise, but, it's much easier to work with. raise FooException("Can't load bar") works, as does f"The flange is elevated by {flange['spronge']} degrees of spronge."


Goes both ways, sometimes there's text to quote:

raise KeyError('"%s" not found.' % name)

f'The flange is elevated by {flange["spronge"]} degrees of spronge.'

I don't normally use many contractions or possessives in my code, but am willing to admit it happens occasionally.


Yep, that's why I like how repr() does it. Guido solved this nicely a long time ago :)


Eh, many programming languages use double quotes for strings, and single quotes for singular characters. Languages that can use single quotes for strings that I know of are ruby and python.


Don’t forget VimL, the language that insanely decided to use double quotes as a “start of comment” indicator, then went back and gave them special meaning based on their position so they either signal the start of a comment or a string.


A different comment character could have been chosen, but this affects nothing. It's not insane.


Lua, and there are others. I favor double quotes for this same reason even when single quotes are allowed.

I'd like «guillemets» but that's going to have to be self-serve...


I use single quotes when the string in question is used like an enumeration:

    set_color('black','white')
And double quotes for strings meant to be read by a human:

    print("Hello there.  How are you?")
And an example with both forms:

    syslog('warning',"unit %s spin rate %f too low",u,rate)
For me, it's an indication of how I expect the string to be used.


And even then, Perl and Ruby (heck, even Bash) have a semantic difference between double- and single-quoted strings. The only other popular general-purpose languages where they're synonymous are PHP, JavaScript, and Lua.


>The only other popular general-purpose languages where they're synonymous are PHP, JavaScript, and Lua.

PHP does treat single and double quotes differently. Contents of single quotes strings are not parsed for variable substitution.


Also Pascal and SQL.


And JavaScript!


Hmm. My reading of PEP 8 on slices is that the spaces surrounding : in slices are optional, and used to implement the later rule "If operators with different priorities are used, consider adding whitespace around the operators with the lowest priority(ies). Use your own judgment; however, never use more than one space, and always have the same amount of whitespace on both sides of a binary operator."

This leads to the following difference between the PEP 8 recommendation and Black:

PEP 8 accepts both of these:

  ham[lower+offset : upper+offset]
  ham[lower + offset : upper + offset]
While Black just uses:

  ham[lower + offset : upper + offset]
Also, this is one that PEP 8 doesn't have a example on, but I think this would be one of the cases in which the space wasn't necessary:

  slice[a.b : c.d]

The "." operator binds so tightly in my mind that it doesn't need the spaces around the ":" to disambiguate. It's at the same precedence level as subscription and function call, and higher precedence than unary + and -.

After typing this all out, I think that it might be the case that the bigger difference is actually in how binary operators are treated. It looks like Black always puts whitespace around binary operators, which contradicts PEP 8's recommendation that you are allowed to vary spacing around binary operators to make precedence clear.

Since Black does allow for leaving in extraneous parentheses to make precedence clear, I wonder why it doesn't allow varying the space around binary operators as well? Of course, it should enforce that the spacing actually does match the precedence, and that the spacing is consistent within an expression. That would allow the following examples which PEP 8 lists as "Yes":

  x = x*2 - 1
  hypot2 = x*x + y*y
  c = (a+b) * (a-b)
While right now Black rewrites them as follows, which PEP 8 lists as "No" (though my reading is that varying the spacing like this is optional, so the following could be accepted as well):

  x = x * 2 - 1
  hypot2 = x * x + y * y
  c = (a + b) * (a - b)


Black does not take existing formatting into account. Doing so would cause non-deterministic formatting (Black would sometimes change its mind about its own formatting and a second pass would cause a different formatting than the first).

With this in mind, it has to enforce a rule around operators. Since any operand might be complex, it's more robust to default to spaces around operands always. Otherwise we would inevitably end up hugging operands with an operator that humans consider too tight. And since that's subjective, there is actually no rule that we can hard-code about that.


> Black would sometimes change its mind about its own formatting and a second pass would cause a different formatting than the first

Why not? I mean, I never built a formatter so idk about the complexity involved, but to me it seems that if Black had a rule like "if you see `a+b` (no spaces), just leave it alone", applying the rule twice shouldn't change anything.

(though I imagine that the interactions of such rules could become hard to understand...)


The whole idea is to _prevent_ people from thinking about formatting, by actually making it impossible to make any formatting decisions. There's exactly one way to format the program and that's it. It's draconian, but that's what's great about it.


That's the feeling I got from the readme, but GP sounds like this particular decision was made not so much for 'philosophical' reasons, as because Black-ing a file twice might give different results. I was curious why :)


I'm new to python, I didn't realize there's a difference, can you help me understand the benefits?


I put it in the README. Let me know if anything is unclear.


I have to admit that I was very excited to begin enforcing black on all of our projects at work - until the double quotes decision. I’m used to single quotes everywhere (except docstrings!).

I’m probably going to still move to black but I know I’m likely to face some pushback now on this one choice, and I don’t yet have the will to defend it.

I also know I’m being mostly unreasonable .. “why is this opinionated tool not perfectly aligned with MY opinions??” .. but feelings.


The double quotes are the only thing that bother me as well. Double quotes are harder to type (on my keyboards) and look more noisy. All other Black formatting I think I could live with. I suppose I can live with double quotes on strings too but I'm not going to like it. ;-)


That's the #1 complaint I have (and hear) about Black. Everything else, I can live with. And honestly, I can live with using double quotes everywhere, especially when I can type single quotes and then let it re-write them. It's just that they currently look really, really odd to me because that's not how Python is traditionally written.


I prefer a quoting convention of single quotes for text identifiers (as they rarely contain quotes) and double quotes for English text (because contractions are common). Thus:

    key['first_name'] 
    print("Isn't this clearer?")


I generally follow this convention:

1. Any string literal that contains either ' xor " will be delimited by the other one. 2. For all other string literals, delimit by " if it's meant for human eyes only, delimit by ' if it's meant for computers as well.


Same, though I'd word the first one as programmatic identifiers.

Adopted that from Erlang, where atoms are single-quoted and text strings are double-quoted.


Actually I prefer standardizing on double quotes and I do that in my code on a regular basis. I know some people use a mix, sometimes single quotes and sometimes double quotes, which is fine, but I prefer consistency in this case.


PEP8 doesn't have a preference between single or double quotes. Black has:

> It will replace the latter with the former as long as it does not result in more backslash escapes than before.

And I think that's good enough (and in compliance with PEP8)


The slices thing seems to follow PEP8.


Everyone has an opinion, and this is theirs. That's kind of the whole point.


Coming from a C background I always stuck with double quotes for strings. Single quotes are used for characters in C. I think double quotes are better anyway because an apostrophe is much more likely to turn up in a string than a double quote itself. I rarely have to manually escape quotes inside strings.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: