-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Regular formatting of multiline expressions #317
Comments
Can you find a reference where this rule comes from? Reading happens left-to-right within a single line. It's not a violation of this rule to use multiple lines. In general, I looked through the diff on your fork but I disagree with many of your assessments. I do see that you like regularity and don't mind extra parentheses. But a lot of people do, myself included. People write code from left to right within a single line and most often think about splitting lines when they reach the line length limit. So splitting close to the right edge of the line generally looks more natural than splitting early. For example, I consider those formattings worse: # proposed
variable = (
some_long_function(
with_long, argument, list
)
)
# current behavior
variable = some_long_function(
with_long, argument, list
) # proposed
variable = (
f(
[long, list]
+ [another, long, list]
+ [yet, more]
)
)
# current behavior
variable = f(
[long, list]
+ [another, long, list]
+ [yet, more]
) In the same vein, I consider your proposed change to force call chaining even on the first call rather overzealous. Black is obviously a dumb machine formatter but it does try to format code like real people would. I know nobody who would naturally format code like this: message = (
"formatting string with {}"
.format(variable)
) but plenty of people format like this (which is the current behavior): message = "formatting string with {}".format(
variable
)
Sorry, I can't respond to every new issue on a daily basis. Design discussions naturally spread longer because they have way more far-reaching consequences for the future of the project. |
I was passive aggressive with those words. I am really sorry about that!
Layout with direction and cohesion guarantees enable skipping over parts safely. Skipping over uninteresting parts speeds up reading and understanding. I do not know about anyone else putting into words this "rule" ("parameters should be right of function name"). So I can give no reference. It is a recent revelation to me, which I see justified again and again since (I see it also in some of black's issues). At least some people also feel it natural to have the arguments right of the function name even for multi-line layout. The evidence is the tropical layout (function calls are like palm trees of different size): # Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
var_three, var_four)
variable1 = function_with_long_name(param1,
param2,
param3)
variable2 = another_function(long_param1,
param2) This layout has obvious drawbacks, but I do see it reappearing/used from time to time - e.g. the first call with the comment is the first "Yes" example from PEP8.
Actually I do mind extra parentheses, but I would choose them over a worse alternative anytime. When reading complex multiline expressions, I do not mind if there are more parens, and the layout is helping - it is properly indented, regular, uninteresting. In my "fork" (it is not intended to be a workable alternative) I have just trivially disabled some optimizations, so it is not giving the best possible layout, but I hoped to show, that the smartness in those optimizations have irregular side effects even on black's code, hindering readability - breaking code at unexpected places.
I do not think it really matters how people wrote the code, once it can be reformatted. The way we write has a factor of lazyness in it, taking different - person dependent - shortcuts. Yes, it would make the code look regular/uniform, but is not this the goal?
Well, maybe its just me, but I expect a code formatter to do a better job than most real people: regular layout without random exceptions ;)
# proposed
variable = (
f(
[long, list]
+ [another, long, list]
+ [yet, more]
)
)
# current behavior
variable = f(
[long, list]
+ [another, long, list]
+ [yet, more]
) Sorry to disagree, but the current behavior is dangerous, not better, as it lays out a very different construct (function call with single argument expression vs expression) the same way: # black
variable = (
[long, list]
+ [another, long, list]
+ [yet, more]
) Do you also feel black's formatting of the first set of of examples acceptable? |
I was just looking at the diffs again - could you explicitly point to any "assessment" in my diffs to black, with which you disagree? |
Although I'm relatively +1 for what's @e3krisztian is showing here, I think the issue is probably too broad. From reading the answer on (my) #527, it seems that aligning the boolean operators Examples from #527
Why do I want this? Complex conditional expressions are usually hard to read, When it comes to just function invocation, I'm not convinced that always adding parens can be justified. I often see this:
I think the L-to-R reading is important for people, and if so, they stick to the formatting in the above 'lucky' cases, but if it really doesn't fit, they give up and just don't. P.S. I do
often enough. It doesn't look unusual at all as soon as the string is long enough. |
OK, I thought about this quite a bit. We won't be adding extra parentheses to disambiguate assignments from calls or force fluent interfaces on first period. Those are overzealous in my view. You are supposed to read the first line of a statement to figure out what is happening. Relying on regularity alone will deceive you. The indented bracketed content is called a "trailer" because it really is just trailing content from the first line. Black's formatting lets you visually navigate from the indented block to the preceding outer line fast. Also, we won't be adding any form of formatting that involves backslashes since that piece of Python grammar should be dropped (it's the single place besides multiline strings that breaks significant indentation). All that being said, we will be definitely fixing some of the more egregious examples of irregularity that stem from unnecessary or missing optional parentheses in Thanks @e3krisztian and @kaste for your thoughtful input and sorry it took me so long to get back to you. |
Operating system: Arch Linux
Python version: 3.6.5
Black version: 18.6b1
Does also happen on master: yes
Function names should start left of their parameters, to maintain left to right reading.
While this might sound natural, in multiline expressions it is surprisingly frequently violated.
Violations result in irregular/strange looking code, that require non-linear scanning to understand.
The examples below are generated by
black -l 40
:Is there any difference?
Method calls, method chaining
All the expected examples are wrapped in an extra
()
-s and thus the expression's internal()
-s are not needed to be repurposed for implicit line continuations.The text was updated successfully, but these errors were encountered: