Closed l0k18 closed 6 years ago
It occurred to me that the same thing as with the optional statement in if blocks could be used as syntax, except the first clause is a conditional that determines if the return is done:
return <condition>; <statement>
though that isn't consistent with using the colon for the list syntax:
return (
<condition>:
<statement>
)
The simple conditional return I can see getting a lot more use, I'm not sure a compound format would be a useful thing (since switch/case/returns can do the same), but being able to abort a return makes error handling shorter.
It's basically a switch case return with implicit fallthough. This is basically what most error handling blocks are. That is, it returns from the function if a condition is true, if not, execution continues.
In current Go this has to be done this way:
if <condition> {
return <statement>
}
This construction is possibly one of the most common patterns you will see in Go source code, and it is only because you can't return on condition but on condition return - this is a major obstacle against consistent error handling.
CC: @mpvl
I mega-support this. This is easily the most obnoxious part of Go because especially while running MySQL queries, every single statement turns into 5 lines of code, with obligatory if err != nil { return err } spread over 4 lines.
This reduces code readability by a lot, because you can only have 6 or 7 steps of actual code logic on a screen, the rest peppered with boilerplate if err != nul { return err }
I appreciate the Go designers' desire for a clean language, but this puts a 400% tax on almost every line of code that can produce an error.
It's not necessary with exception handling, I agree that it's a dirty design pattern. But we're left with nothing, except this constant drone ya-da-ya-da-ya-da-ya-da of if err != nil {return err}
Keep in mind also that gofmt is hard biased against multiple statements on one line, and gofmt is also a near-mandatory tool to use. So it's a perfect storm that results in some pointlessly verbose code that's significantly less readable.
I could live with either solution:
1.) Conditional returns.
2.) A change to gofmt that allows multiple statements per line.
Yet another bad thing with Go insistence about 4-line error handling is that the only real way to reduce the amount of boilerplate code is to flip the logic so you don't return, but do nesting hell instead, which is another anti-pattern:
if doSomething() {
if doSomething() {
if doSomething() {
if doSomething() {
if doSomething() {
}
}
}
}
}
Go really is conspiring to force you into some very poor error handling patterns unless you want every single statement to be appended with 4 lines of boilerplate if (err != nil) {return err}
80% of the code on my screen right now is boilerplate that you have to think around when you're trying to understand the code flow. I feel like Go is winning the battle and losing the war in this regard.
I think the Go designers' idealism is getting just a little bit out of hand with error handling, because there's no combination of tools that allows you to make readable code when there's a lot of error handling (MySQL, I/O etc).
I think that bearing in mind that some of the neat multi-clause things like the map key check and the pre-test if statement clause hint towards an optional test clause for returns, it's such a small change and enables elimination of several kinds of vertical bloat of the code (both error handling and fallthrough statement all by itself pointlessly in a switch case block).
It amounts to something like a macro to implement it, as it is simple to parse it back to if condition { statement }. It's a breaking change but it would not be difficult even to write a preprocessor that rewrites it back if for whatever reason you must use an older version of the compiler.
What about if err != nil { return err }
?
gofmt always adds newlines to the return call in an if block.
We already have a way to write a conditional return:
if err != nil {
return err
}
This proposal suggests a second way to write a conditional return:
return err if err != nil
There's no obvious reason to only permit the trailing if
on return
statements; it is generally useful. But then, there is no obvious reason to permit the trailing if
at all, since we already support the preceding if
. In general we prefer to have fewer ways to express a certain kind of code. This proposal adds another way, and the only argument in favor is to remove a few lines. We need a better reason to add this kind of redundancy to the language. We aren't going to adopt this.
Is there an existing issue for formatting if err != nil { return ... }
on a single line? I know I've seen that suggested a few times.
I agree that the 'statement after the return' is ambiguous. And
return condition; statement
isn't terribly clear either. But what about a new keyword to indicate this - I can't think of anything short and snappy. And to go back to what has already been done what about this then - try to look at it like you never saw it before:
if statement; condition {}
or the other notable one:
x, ok := MapVariable[key]
or for that matter
a, b = 1, 2
I considered and rejected the if after return because of how it muddles up the syntax of return and if. You could change it to 'when' maybe?
return expression when condition
When is a word that I can't see as any kind of competition for memorable variable names. I thought about ? but I don't like that one and it sorta collides with c++'s
But it feels non-idiomatic to me. But I'm aiming at several constructs with this, both fallthrough cases and if {return}. I personally would like the fallthrough removed, as it is completely commutable with a regular if statement in almost every way. So instead of fallthtrough you have return conditional; expression.
This clarifies the use cases for switch/case blocks. Plus it removes a more wordy alternative to an if block that if anyone's honest, will tell you they don't use though it seemed like a nice idea at first. I certainly thought that. I use cases a lot, for anything more than one condition. I tried fallthrough a few times and eventually decided it was clearer to use an if before the switch anyway.
The other thing I just thought of was using a comma to separate the condition, but then I remembered tuple returns. Colon came up as well, but it isn't logical as the symbol is generally used as part of declarations or section headings, mainly definitions. Actually on that note I know it's C idiom but since a case condition has to be on its own line in go anyway, actually it could also be removed. It has one weird and cool feature in vscode - when you type a case it unindents it immediately you put the character at the end. But it's entirely unnecessary. It implicitly is followed already by a semicolon.
It's my view that valid and coherent changes to the language that break code really need to pop, because of how well designed it already is. And I would submit to you that you may even want to remove some things. The colon on cases and the optional inline if statement are good examples. The latter particularly becomes redundant with a conditional return for a large amount of use cases, and the remaining cases I can suggest some patterns with methods and pass-throughs that can make this happen anyway.
and goto and labels! Damn, who actually uses those? If they were kept I would want to change the label so it's on the same line, we don't need labels on separate lines because most of the time you'll probably decide to write a function instead.
There is two main threads in the discussions about improvements to Go to put into version 2, generics (cough) and error handling.
This is the latter.
In the most usual, and idiomatic pattern, error handling in Go looks like this:
You can shorten it to this:
But what I am suggesting would look like this:
So it would be, as syntax:
Optionally the if block could exactly match the header of a standard if block, so this would be the syntax of return afterwards:
You can also probably imagine these being used similarly to switch/cases like this:
These could be simplified by making the syntax a little different again for lists:
following the convention for import, var, const, and others (and yes, maps). Or maybe parentheses would be more appropriate, but this would replace two or more conditional return statements. These would behave a lot like switch statements but would specifically assist with error handling.
And while I'm on returns, I think that the final return should be implicit with a named return variable.
While I am talking about switch/case blocks, I think also that
fallthrough
should have a shorter form. Perhaps by adding 'if' as a possible label header, which implies fallthrouogh.I find myself using switches a lot and I think that if certain cases, such as the return, and the fallthrough, had more concise syntax, that people would use them and all the error handling gotchas could be eliminated.