If you were like me, a pure Java developer before writing Go, you must be wondering why Go doesn’t support the ternary operator like return a > 1 ? 0 : 1
.
Most mainstream languages like C and Java are supportive of ternary operators; languages like Python and Ruby support the simplified if-else one-liner, such as a = 0 if a > 1. However, Go is not among them. And it is not only about adding operators but also a concept of coding in a more convenient way, such as the ?: expression can be perfectly replaced by if-else, but what if you are required to duplicate it dozens or hundred times? You must be seeking the optimizations without hesitation.
if a > 1 {
return 0
else {
return 1
}
No Ternary Operator in Go
As early as 2012, there was a discussion on whether to add ternary operators, which was rejected finally and the answer was added to the FAQ.
The reason ?: is absent from Go is that the language's designers had seen the operation used too often to create impenetrably complex expressions. The if-else form, although longer, is unquestionably clearer. A language needs only one conditional control flow construct.
This answer does not satisfy all, and there are still proposals (proposal in 2017)in Github issues in request to have it. Personally, I keep a conserved attitude towards the Go team’s perspective and want to “beat ” their reasons one by one.
Reason 1: Explicitness
if-else can fulfill tasks, but the trade-off is “sacrificing” my keyboard and fingers. For example, using if-else instead of ?: in the previous case means I tap the keyboard at least 13 more times ( if + else + { + { + } + return
), the number can grow exponentially in a production project.
Ternary operator can not only be used in return, and variable assignment, but also in function parameters, printf parameters, etc. We can see an obvious duplicated code if changing into if-elsein the printf case below.
printf("I’m %s 21 years old, so I %s drink", age > 21 ? "above":"below", age > 21 ? "can" : "cannot")
// if - else, duplicated code
if age > 21 {
printf("I’m above 21 years old, so I can drink")
} else {
printf("I’m below 21 years old, so I can drink")
}
Generally, duplicated code is a bad smell that the code readability is reduced even though we encapsulate an additional function to lessen the duplicated code. Looking at the print method only, the complete logic is torn into pieces.
if age > 21 {
print("above", "can")
else {
print("below", "cannot")
}
// wrap function
func print(a string, b string) {
printf("I’m %s 21 years old, so I %b drink", a, b)
}
if-else has a transformation, where initialization variables are used instead of else, changing the above example into the following. It is more concise, but loses invariance and still in low readability.
b := 0
if a <= 1 {
b = 1
}
return b
Reason 2: Legibility
Legibility is a very argumentative concept. At least, I think the readability of return a > 1 ? 0:1
is not weaker than if-else. But I cannot tell whether there is bias based on my years of Java experience. And from the various comments on the proposal, I suppose the Go official considers the poor readability caused by abusing the ternary operator, not by the ternary operator itself, such as the multi-level nested expressions like a = b > 100 ? 99 : ( b > 1000 ? 999 : (b > 10000 ? 9999 : ( b > 100000 ? 99999 : …. ))))
. Converting it to if-else makes it more understandable.
if b > 100 {
a = 99
else if b > 1000 {
a = 999
else if b > 10000 {
a = 9999
....
However, it is not persuasive enough to say no to an operator that brings efficiency just because it has a risk of being abused.
Reason 3: Not all languages support ternary operator
Besides Go, there are some other languages that don’t support ternary operators either, such as Rust, whose team also gives a reason.
Rust tries to avoid having multiple ways to do the same thing. Furthermore, the : symbol is already more overloaded than I would like, and classic ternary syntax would be grammatically ambiguous with the already-accepted type ascription RFC. Furtherfurthermore, there are vague plans to use the ? symbol for language-level error-handling support in the future.
But they also mention their future plans for ? and : operators, right?
Alternatives
Go users are still working tirelessly to propose other similar optimizations to simplify if-else after the ternary operator failed.
Proposal conditional-assign (?=) for limited ternary operator functionality hopes to implement ?= to fulfill one-line if-else and variable assignment, such as a ?= a > 1, 0, 1. This proposal was not passed, either.
Proposal Support inline “if” statement syntax, which hopes to have the one-liner if-else as Python and Ruby, was also rejected due to insufficient attention and support.
As is seen, the Go team will probably not consider adding the ternary operator, no matter how many times they are asked. Turning to alternatives is the only way out in short term.
IDE Template
We can create templates with IDE to simplify code generation and avoid the duplicated if-else. For example, we can create a Live Template named tern in IntelliJ.
Then we can use tern where if-else is needed, and enter the relevant expressions in the three variables.
Generics Ternary Operator
A better solution is from StackoverFlow, provided by a user, supporting the implementation of generics.
func If[T any](cond bool, vtrue, vfalse T) T {
if cond {
return vtrue
}
return vfalse
}
Then we can turn the previous example into return If(a > 1, 0, 1) just as handy as the ternary operator. Try it yourself here.
The End
I enjoy the convenience brought by the ternary operator, however, the Go team stays firm on not adding it, though there are always proposals around. And we can rely on other approaches to improve our coding efficiency before the Go official actually changes their mind.
Thanks for reading!
Reference
https://github.com/golang/go/issues/33171
Note: The post is authorized by original author to republish on our site. Original author is Stefanie Lai who is currently a Spotify engineer and lives in Stockholm, original post is published here.
Note: with this solution the parameters are all eagerly evaluated. Both the true and false responses are evaluated every call. The "normal" if statement solution, as well as built in ternary operators, provide short-circuit evaluation so the unused response is never evaluated. This may or may not be a problem but must be kept in mind if using the proposed technique.