Why Python, Go and Rust Don’t Use the Ternary Operator
Daniel Hayes
Full-Stack Engineer · Leapcell

When programming, we often need to make conditional judgments and choose to execute different blocks of code based on the result. In many programming languages, the most common way to do this is through the ternary operator. However, Python does not support the ternary operator. Interestingly, two of the most popular emerging languages, Go and Rust, also do not support it!
Why doesn't Python support the ternary operator? This article will mainly analyze the process behind Python's design of conditional syntax, explaining why it adopted a unique implementation. At the same time, we’ll examine why other languages have also abandoned the traditional ternary operator.
What Is the Ternary Operator?
The ternary operator usually refers to ?:
, with syntax in the form of: condition ? expression1 : expression2
. If the condition is true, it evaluates to expression1
; otherwise, it evaluates to expression2
.
The simplified form a ? b : c
can be read as "if condition a
is true, then return b
, otherwise return c
."
The ternary operator is a simplified version of a standard if-else structure and is commonly used to perform conditional checks and return values in a single statement.
// Regular if-else if (a > b) { result = x; } else { result = y; } // Simplified version result = a > b ? x : y;
Many programming languages have adopted this syntax design, including C, C#, C++, Java, JavaScript, PHP, Perl, Ruby, Swift, and more. Without a doubt, it has long been the mainstream design approach in programming languages (and still is today).
This syntax is very concise and efficient, and its readability is also strong (once you're familiar with it), which makes it quite popular.
However, it’s not without flaws. Python is the most well-known challenger to this design approach. Let’s explore why Python chose a different path.
The Python Community Vote
Python was released in 1991, but for the next 15 years, it only had if-else syntax for conditionals and did not support ternary operators or other conditional expressions. Before conditional expressions were introduced in 2006, the community engaged in a long and complicated debate—it can be said that this was a difficult syntax feature to finalize.
Originally, due to repeated requests to add an if-then-else (ternary) expression, PEP 308 – Conditional Expressions was proposed in February 2003. The goal was to select a solution that most of the community could support.
Soon, several proposals emerged within the community, aside from a small group that preferred doing nothing:
(1) Punctuation-based ternary operator
This is the conventional ternary operator, using the same syntax mentioned earlier:
<condition> ? <expression1> : <expression2>
This proposal was quite popular, and some developers even submitted implementation code. However, Guido rejected it for two reasons: the colon already had many uses in Python (even though ambiguity was unlikely since the question mark would require a matching colon); and for those unfamiliar with C-like languages, the syntax could be difficult to understand.
(2) Constructed with existing and new keywords
Introduce a new then
keyword and combine it with the existing else
:
<condition> then <expression1> else <expression2>
Its advantages included clarity, no need for parentheses, no change to existing keywords' semantics, low risk of being mistaken for a statement, and no overloading of the colon. The downside was that adding a new keyword would be costly in terms of implementation.
(3) Other proposals
These were similar in spirit to the second approach but did not gain as much support:
(if <condition>: <expression1> else: <expression2>) <condition> and <expression1> else <expression2> <expression1> if <condition> else <expression2> cond(<condition>, <expression1>, <expression2>)
Notably, the (if <condition>: <expression1> else: <expression2>)
format is a flattened version of the regular if-else syntax, easy to understand but requires parentheses. This can cause confusion with generator expressions and requires special handling of the colon by the interpreter.
Also noteworthy is <expression1> if <condition> else <expression2>
, which was the originally recommended proposal in early versions of PEP 308. However, some people disliked this form because it didn't place the condition at the beginning. Additionally, if expression1
is long, it's easy to overlook the condition entirely.
Here were all the options voted on at the time:
A. x if C else y
B. if C then x else y
C. (if C: x else: y)
D. C ? x : y
E. C ? x ! y
F. cond(C, x, y)
G. C ?? x || y
H. C then x else y
I. x when C else y
J. C ? x else y
K. C -> x else y
L. C -> (x, y)
M. [x if C else y]
N. ifelse C: x else y
O. <if C then x else y>
P. C and x else y
Q. any write-in vote
In general, developers wanted to introduce some form of if-then-else expression, but after the vote, no option gained a clear majority. The disputes boiled down to: whether to use punctuation, reuse keywords, reuse parentheses, introduce new keywords, or add new syntax...
Because the votes were too fragmented, the PEP was rejected at the time. The PEP stated: “One of Python’s design principles is to maintain the status quo in the face of uncertainty.”
Problems with Using and-or
for Conditional Selection
The voting event above took place in March 2004, but discussions on this topic didn’t die down after PEP 308 was rejected. Developers were still looking for a concise way to replace if-else
.
In September 2005, someone on the mailing list proposed changing the logic of the and
and or
operators in Python 3.0. The idea was to simplify and
and or
so that they would always return boolean values, instead of returning the last evaluated operand.
The reason for this proposal was that the author had used the form <condition> and <expression1> or <expression2>
to perform conditional selection. However, Python's behavior in this regard differs from some other languages, and if used carelessly, it can lead to bugs!
Take a look at the following two examples. What results would you expect?
a = True and True or "Python" b = True and False or "Python"
For <condition> and <expression1> or <expression2>
, if the condition is false, it will directly evaluate and return expression2
. If the condition is true, it evaluates expression1
; if expression1
is also true, it won't evaluate expression2
. But if expression1
is not true, it will evaluate and return expression2
.
So in the examples above, a
evaluates to True
, while b
results in "Python"
.
Python handles truthiness in a special way. For instance, the author of that email encountered a situation where expression1
was a complex number 0+4i
, which is evaluated as False
in truthiness. As a result, the final return was not the intended expression1
, but rather expression2
!
Before a better solution was introduced, the and-or
pattern was a relatively common way to perform conditional selection. PEP 308 also mentioned this approach and pointed out that if expression1
evaluates to false, it could cause issues. It even labeled this pattern as ugly and confusing.
That email reignited community discussion about conditional syntax, and prominent developers began weighing in.
From today’s perspective, it's clear that developers were dissatisfied with the status quo of if-else
. However, the popular and-or
workaround wasn’t good enough, so there was a strong desire for Python to introduce a new, standardized syntax to solve this pain point.
A Unique Conditional Expression
After 10 days of email discussion, Guido van Rossum eventually decided to introduce a conditional expression with the syntax X if C else Y
. As a result, PEP 308 was reopened and updated, and the feature was implemented in Python 2.5 the following year.
This is the syntax we previously mentioned that some people found uncomfortable—because the condition isn't placed at the beginning.
So why did this end up being the winning design? Was it the optimal choice?
Undeniably, the decisive factor was Guido himself. Since no majority consensus emerged during the community vote a year and a half earlier, he exercised his power as the BDFL (Benevolent Dictator For Life) to choose what he considered the best solution.
X if C else Y
is very easy to understand and highly readable. It follows Python’s style of “explicit is better than implicit” by using intuitive, natural-language-like if-else
instead of potentially confusing punctuation. This is similar to Python’s use of and
and or
instead of symbols like &&
and ||
.
Although the adjusted order of this syntax might take some getting used to, the implementation has significant advantages. First, it only reuses the existing keywords if
and else
, without introducing new keywords like then
or when
, or any additional syntax elements. It’s also less cumbersome than the (if <condition>: <expression1> else: <expression2>)
format.
Second, to verify the effectiveness of X if C else Y
, Guido reviewed all usages of the and-or
combination in the standard library and found that each instance of C and X or Y
could be replaced with X if C else Y
. The state of the standard library proved that the new syntax was viable.
Looking back at this history, we can identify a clear thread: Python did not adopt the ?:
ternary operator primarily because it doesn’t align with the language’s emphasis on clarity and straightforwardness. Instead, it introduced the X if C else Y
expression to eliminate the pitfalls of the and-or
pattern. This design is concise, readable, and very useful.
Overall, Python’s designers place great value on readability and maintainability. Choosing not to adopt the ternary operator and instead creating a new conditional expression was the result of open discussion, careful evaluation, and balanced trade-offs.
Why Don't Go and Rust Support the Ternary Operator?
After exploring Python's design decisions, let’s look at two of the most popular languages in the "opposing camp."
First, Go. The Go language’s official FAQ includes a specific question: “Why does Go not have the ?:
operator?”
Go does not support the ?:
operator and instead recommends using the native if-else
syntax. The documentation provides a brief explanation in just one paragraph:
Go does not have a
?:
operator because the designers have seen it used to create confusing, complex expressions. Althoughif-else
is longer, it is undoubtedly clearer. A language only needs one conditional control flow structure.
Next is Rust. Its official documentation doesn’t seem to explain why the ternary operator is unsupported. But with further research, I found it has an interesting backstory: in June 2011, Rust actually did introduce the ternary operator (#565
), but within six months, the designers realized it was redundant and removed it (#1698
, #4632
)!
Why was the ternary operator considered redundant in Rust? Because unlike many other languages, Rust’s if
is not a statement, but an expression. This means you can assign the result of an if
expression directly to a variable:
// If the condition is true, you get 5; otherwise, 6 let number = if condition { 5 } else { 6 };
This syntax is simple and clear—it’s just like using the familiar if-else
for assignment. Replacing it with a ternary operator would be unnecessary, even excessive.
Additionally, Rust uses curly braces to define code blocks, so the content inside the braces can contain multiple expressions and even support line breaks, as in the following example:
let x = 42; let result = if x > 50 { println!("x is greater than 50"); x * 2 // This is an expression, and its value is assigned to `result` } else { println!("x is less than or equal to 50"); x / 2 // This is also an expression, returned and assigned to `result` };
This kind of usage would be impossible in Python. The most crucial difference lies in the fact that Rust’s if
is an expression, not a statement.
The distinction between the two concepts is:
- Expression: A piece of code made up of variables, constants, operators, etc., that evaluates to a value and can be used within other expressions or statements.
- Statement: A single instruction or a group of instructions that perform an action, such as assignments, conditionals, or loops. Statements do not return values (or return nothing), and cannot be used in expressions.
Besides Rust, there are other programming languages where if
is an expression, such as Kotlin, Scala, F#, and Swift. Theoretically, these languages don’t need a ternary operator either. (Side note: Swift is an exception—it does have a ternary operator. Kotlin also has a ?:
operator, but note that the two symbols are connected. For example, val result = a ?: b
means: if a
is not null, assign it to result
; otherwise assign b
.)
Because of these language-level design differences, Rust and Python/Go approach the ternary operator question from inherently different starting points. Once you understand this distinction, you gain a clearer perspective on programming languages.
So, back to the original question: why do some programming languages not adopt the mainstream ternary operator syntax?
It’s undeniable that ?:
is a concise and useful design. However, the downside of using punctuation is that it can be overly abstract and less readable than if-else
. Furthermore, different language philosophies and usage habits lead to different choices.
Python, after many twists and turns, ultimately came up with its own unique conditional expression syntax. Go explicitly states that it does not support the ternary operator. Rust introduced it and then removed it—mainly because of its fundamental use of if
as an expression.
We are Leapcell, your top choice for hosting Rust projects.
Leapcell is the Next-Gen Serverless Platform for Web Hosting, Async Tasks, and Redis:
Multi-Language Support
- Develop with Node.js, Python, Go, or Rust.
Deploy unlimited projects for free
- pay only for usage — no requests, no charges.
Unbeatable Cost Efficiency
- Pay-as-you-go with no idle charges.
- Example: $25 supports 6.94M requests at a 60ms average response time.
Streamlined Developer Experience
- Intuitive UI for effortless setup.
- Fully automated CI/CD pipelines and GitOps integration.
- Real-time metrics and logging for actionable insights.
Effortless Scalability and High Performance
- Auto-scaling to handle high concurrency with ease.
- Zero operational overhead — just focus on building.
Explore more in the Documentation!
Follow us on X: @LeapcellHQ