avatarbo leo

Summary

Python, Go, and Rust do not support the traditional ternary operator due to their design philosophies emphasizing clarity and readability, instead favoring unique conditional expressions or structures.

Abstract

The article delves into the reasoning behind Python's decision to not adopt the traditional ternary operator "?:", which is common in many other programming languages. Despite frequent requests from the community, Python's design philosophy, which values readability and simplicity, led to the creation of its own conditional expression syntax "X if C else Y". This decision was made after extensive community debate and voting, with the final syntax chosen by Python's creator, Guido van Rossum. Similarly, Go and Rust also eschew the ternary operator; Go prefers the clarity of the "if-else" statement, while Rust's language design allows "if" to be an expression that can directly assign values, making the ternary operator redundant. The article emphasizes the importance of understanding language design history and philosophy to improve programming skills and thinking.

Opinions

  • The Python community engaged in a long and complex debate before arriving at the current conditional expression syntax, highlighting the importance of community input and the value of clear and intuitive syntax in Python.
  • Guido van Rossum's role as the Benevolent Dictator For Life (BDFL) was crucial in resolving the impasse in the Python community regarding the adoption of a conditional expression.
  • The Go language's design decision to exclude the ternary operator is based on the belief that a single, clear "if-else" control flow structure is preferable to the potentially confusing use of the ternary operator.
  • Rust initially included a ternary operator but later removed it, as its language design, which treats "if" as an expression, already provided a clear and concise way to perform conditional assignments without the need for a ternary operator.
  • The article suggests that understanding the nuances of language design, such as the rationale behind the absence of a ternary operator in Python, Go, and Rust, can lead to clearer and more flexible programming thinking.
  • The preference for readability and maintainability over brevity is a common theme in the design decisions of Python, Go, and Rust regarding conditional logic.

Why Don’t Python, Go, and Rust Support the Ternary Operator?

When programming, we often need to make conditional judgments and choose different statement blocks based on the result of the condition. In many programming languages, the most common way is to use a ternary operator. However, Python does not support ternary operators. Interestingly enough, two of the most popular emerging languages, Go and Rust, also do not support them!

Why doesn’t Python support ternary operators? This article will mainly analyze the process of designing conditional selection syntax in Python and explain why it adopts its current unique implementation solution. At the same time, we will also examine why other languages are abandoning traditional ternary operators.

Before we begin, I want to emphasize that this article focuses only on a very small grammar point. Because paying attention to details can reveal true skills, delving into the reasons behind language design — history and philosophy — can enable us to have clearer and more flexible thinking when programming.

What is a ternary operator?

The ternary operator usually refers to the “? :”, its syntax form is: condition ? expression1 : expression2. If the condition is true, then take expression1, if not true, then take expression2.

The simplified syntax form “a ? b : c” can be read as “if the condition a is met, it becomes b; otherwise, it becomes c”.

The ternary operator simplifies the ordinary single-level if-else structure and is commonly used to achieve both conditional judgment and value retrieval operations in one statement.

// Regular if-else
if (a > b) {
    result = x;
} else {
    result = y;
}

// Simplified writing
result = a > b ? x : y;

Many programming languages adopt this grammar design, such as C, C#, C++, Java, JavaScript, PHP, Perl, Ruby, Swift, and so on. There is no dispute that it is the mainstream design solution in the programming language field (still to this day).

This grammar is very concise and efficient, and the code has strong readability (if you are not new to it), which is loved by many people.

However, it is not without flaws. Python is the most famous challenge of this grammar design. Next, we will see why Python takes a different approach.

Voting in the Python community

Python was released in 1991, but in the following 15 years, besides if-else syntax, it did not support ternary operators and other conditional expressions. Moreover, before the introduction of conditional expressions in 2006, there was a long and tortuous debate within the community. It can be said that this is a grammar that was designed with great difficulty.

Initially, due to frequent requests for adding if-then-else (ternary) expressions, PEP 308 — Conditional Expressions was proposed in February 2003 to select a solution supported by the majority of the community.

PEP 308 — Conditional Expressions

Soon, apart from a few people who hope to do nothing, several solutions appeared in the community:

1. Ternary operators constructed using punctuation marks

That is the regular ternary operator, which follows the grammar introduced earlier.

<condition> ? <expression1> : <expression2>

The demand for this proposal is quite high, with developers even submitting implementation code. However, Guido has given two reasons for opposition: colons already have many uses in Python (even though it doesn’t create ambiguity because the question mark needs to match the colon); it is difficult for people who are not familiar with C-derived languages to understand.

2. Using existing and new keywords

Introduce a new “then” keyword, combined with the existing “else” keyword:

<condition> then <expression1> else <expression2>

Its advantages are clear and simple, without the need for parentheses, without changing the semantics of existing keywords, unlikely to be confused with statements, and does not require overloading colons. The disadvantage is that the implementation cost of introducing new keywords is relatively high.

3. Other approaches

Similar to the previous solution in terms of approach but lacks the high support level of the two types mentioned above.

(if <condition>: <expression1> else: <expression2>)
<condition> and <expression1> else <expression2>
<expression1> if <condition> else <expression2>
cond(<condition>, <expression1>, <expression2>)

It is worth mentioning that (if <condition>: <expression1> else: <expression2>) is a flattened version of the regular if-else syntax, which is easy to understand but has the disadvantage of requiring parentheses, making it easy to confuse with generator expressions and requiring special treatment by the interpreter for colons.

Another noteworthy point is <expression1> if <condition> else <expression2>, which was recommended in the earliest version of PEP-308. However, some people feel uncomfortable with this style that does not place the condition at the beginning. Moreover, when “expression1” is long, it is very easy to overlook its condition.

All design proposals involved in voting at that time were:

a hundred flowers bloom;

Overall, developers hoped to introduce some form of if-then-else expression, but no proposal gained an absolute advantage after the vote. In summary, the main points of disagreement are: whether to use punctuation marks, whether to reuse keywords, whether to reuse parentheses, whether to introduce new keywords, and whether to introduce new syntax…

Due to the scattered votes, this PEP was rejected at that time. The PEP states: “One design principle of Python is to maintain the status quo when unsure which path to take.

The problem of using “and-or” for conditional selection

The voting event mentioned above occurred in March 2004. However, even after the rejection of PEP, discussions on related topics did not die down because everyone was always looking for a concise way to replace “if-else”.

In September 2005, someone in the email group proposed changing the logic of the “and” and “or” operators in Py3.0. The proposal suggested simplifying the “and” and “or” operators to always return boolean values instead of returning the last evaluated argument.

The reason for initiating this proposal is that he used <condition> and <expression1> or <expression2> to implement conditional judgment and selection. However, this writing style behaves differently in Python compared to some other languages. If used carelessly, it may cause bugs!

Take a look at these two examples below. What do you think their results will be?

a = True and True or "PythonCat"

b = True and False or "PythonCat"

For <condition> and <expression1> or <expression2>, if the condition is false, expression2 will be evaluated directly and the result will be returned. If the condition is true, expression1 will be evaluated first. If it is also true, expression2 will not be evaluated further. If expression1 is not true, then expression2 will be evaluated.

Therefore, in the above example, a would be “True”, while b would get “PythonCat”.

Before a better solution is found, the “and-or” is a common way of conditional selection. PEP-308 also mentions it and points out that when “expression1” is false, this approach is considered ugly and confusing.

This email has once again sparked discussions in the community about conditional selection syntax, with many experts joining in.

From my current perspective, it seems that developers are not satisfied with the status quo of “if-else”. However, the popular “and-or” writing style at that time was not good enough. Therefore, everyone expects Python to design new standardized syntax to address this pain point.

Unique conditional expression

After 10 days of email discussion, Guido van Rossum finally decided to add a conditional expression with the syntax X if C else Y. Therefore, PEP-308 was reopened and updated, and it was quickly implemented in version 2.5 the following year.

As mentioned earlier, this solution made some people uncomfortable because it did not place the conditional logic at the beginning.

So why did it end up being the winner? Is it the optimal design?

Undeniably, Guido played a decisive role. Since there was no majority opinion in the community vote one and a half years ago, he exercised his decision-making power as BDFL (Benevolent Dictator For Life) and determined what he believed to be the best solution.

X if C else Y is very easy to understand and has high readability. It continues the style of “explicit is better than implicit” by using an intuitive colloquial “if-else” instead of introducing punctuation that could confuse, just like how Python chooses “and” and “or” as words instead of using symbols like “&&” and “||,” which have similar meanings.

Although adjusting the syntax order may feel unfamiliar at first, this implementation has many advantages. First of all, it only needs to reuse two keywords — “if-else,” without introducing additional grammar elements such as “then” or “when,” unlike (if <condition>: <expression1> else: <expression2>) which can be cumbersome.

Secondly, to validate the effectiveness of X if C else Y , Guido examined all combinations of “and-or” usage in the standard library and found that those expressions written as C and X or Y can be replaced by X if C else Y . The situation in the standard library proves that this new syntax is feasible.

Looking back on this history, we can identify a clue: Python did not design a ternary operator “?:” mainly because it does not align with Python’s clear and intuitive design style. The adoption of the X if C else Y design was primarily intended to eliminate the pitfalls of “and-or” usage. This design is concise, easy to read, and very useful.

Overall, Python designers highly value readability and maintainability. The decision not to use a ternary operator but instead create a conditional expression syntax is the result of open discussions, careful evaluations, and trade-offs.

Why don’t Go and Rust support the ternary operator?

After examining the design reasons for Python, let’s now examine the two most popular languages in the “villain camp”.

First is Go language, the FAQ on its official website specifically lists a question: “Why does Go not have the ?: operator?”.

Go language does not support the “?:” operator and instead recommends using native “if-else” syntax. The explanation in the documentation is very brief, with only one paragraph:

Go language does not have the ?: operator because its designers often saw it being used to create complex expressions that are difficult to understand. Although if-else form is longer, it is undoubtedly clearer and easier to understand. A language only needs one conditional control flow structure.

Next is Rust language, there seems to be no explanation about not supporting ternary operators in its official documentation. However, after researching further, I found an interesting story: In June 2011, Rust once introduced ternary operators (#565), but six months later, designers realized that this feature was unnecessary and removed it (#1698,#4632)!

Why are ternary operators unnecessary in Rust? Because if the syntax is not like other languages as a “statement”, but rather an “expression”, which means you can directly assign an if expression to variables.

// If the condition is true, get 5; otherwise, get 6.
let number = if condition { 5 } else { 6 };

This grammar form is simple and clear enough. Isn’t it just using the familiar “if-else” directly for assignment? It’s so convenient. If replaced with a ternary operator, it does feel like adding something unnecessary.

In addition, Rust uses curly braces to delimit code blocks, so the curly braces in the above example can contain multiple expressions and also support line breaks. For example:

let x = 42;
let result = if x > 50 {
    println!("x is greater than 50");
    x * 2 // This is an expression that assigns the returned value to "result".
} else {
    println!("x is less than or equal to 50");
    x / 2 // It is also an expression, assigning the returned value to result.
};

This usage is not possible in Python. The key difference is that in Rust, “if” is an expression rather than a statement.

The difference between these two concepts is:

  • An expression typically refers to a code snippet composed of variables, constants, operators, etc., which can be evaluated and used in other expressions or statements.
  • A statement typically refers to a single instruction or group of instructions that accomplish a certain task, such as assignment statements, conditional statements, loop statements, etc. It does not have a return value (or it may be empty) and cannot be used for assignment operations. In addition to Rust, there are also some programming languages where “if” is an expression rather than a statement. For example Kotlin, Scala, F#, Swift. In theory, they do not need to use the ternary operator either. (Side note: Swift is an exception as it also has the ternary operator. Kotlin has the “?:” operator; please note that the two symbols are combined. “val result = a ?: b” means if “a” is not null then assign it to “result”; otherwise assign “b” to “result”.)

Due to this language design difference at the fundamental level, when facing the question of whether or not to support the ternary operator,” Rust and Python/Go have naturally different starting points for their thinking process.” Knowing this difference will give us a clearer understanding of programming languages.

Returning to our main question in this article: Why do some programming languages not adopt mainstream syntax for ternary operators?

Undeniably,”?:” indeed represents a concise and convenient design; however, the negative impact of punctuation marks makes it more abstract and less readable compared with “if-else”. Additionally, different language design styles and usage habits can lead to different choices.

After going through twists and turns, Python finally designed its unique conditional expression. Go explicitly states that it does not support the ternary operator. Rust designed it initially but later abandoned it, mainly due to the language foundation of “if” expressions.

If you want to learn more about Python, please subscribe to the “Why Python” section. Let’s discuss this together with all the people who love Python and programming, starting from a fresh perspective and improving our programming skills. If you have gained knowledge from this section, please follow me. Thank you.🤩

Python
Programming
Ternary Operator
Recommended from ReadMedium