Ternary operator

I, for one, emphatically throw my hat into the ring AGAINST the standard C-style ternary operator

And this is definitely unnecessary functionality with if-else expressions.

The phrase you are looking for is “easier to read”.

ternary operator is the most lopsided operator there is because it is a postfix on the condition. Imagine reading from right to left, x = a, ok a gets assigned to x, now ?, WTF? x = a ? b, WTF?, x = a ? b :, Huh?. Compare that to x = if, OK at this point I know x is getting assigned the result of a conditional.

The phrase you are looking for there is “hard to read” or “unobvious”. And they will likely have to repeatedly look it up.

They see that and they already know what an if-else is. Only difference is that it has a value instead of continuing the artificial Java and C limitation that if has no value. Lots of other languages already have if-expressions and this is easy for them to read. I think a non-programmer could figure out what x = if(a) b else c means.

Certainly no one is talking about removing conditional expressions. Ternary operator exists ONLY because in C if was a statement not an expression. With that limitation gone ternary operator has no reason to exist.

1 Like

It’s interesting to compare Swift’s reasoning for having the ternary operator instead of if else as expression.

In this message Chris Lattner lists the cons of if then else expression:

  • It is substantially more verbose than ?:, so much so that it obscures the logic that was trying to be captured.
  • It looks like if statement, however it is semantically different
  • It forces indenting a lot when branches have long expressions

Then he lists the pros of the ternary operator:

  • It is extremely concise, and covers a very common pattern.
  • It is pervasively standardized in a very wide range of languages.
  • It’s weird syntax reduces the odds that people would flow it out and use very large expressions in it.
  • It chains well for multiple conditions because of its associativity.

However he also admits the cons of the latter:

  • ?: is ugly and magic, and is an additional thing people have to learn if coming to swift without encountering a C family language.
  • it is unfortunate that it uses “?” in particular, since they’d prefer that to be associated with optionals.

And here he even said that he’d love to see the weird ?: ternary operator get nuked and replaced with an if/else expression of some sort.

The links were taken from Commonly Rejected Changes page, so I believe these messages represent the Swift team’s point of view.

In the end he says “we only change things when there are strong reasons” and I think this applies to the situation with the ternary operator in Kotlin too :wink:

5 Likes

+1 for ternary

I hate that everything for ternary is on place and you can in fact create one:

operator fun <T> Boolean.plus(firstValue: T): FirstValue<T> = FirstValue(this, firstValue)
operator fun <T> FirstValue<T>.minus(secondValue: T): T = if (bool) firstValue else secondValue
data class FirstValue<out T>(val bool: Boolean, val firstValue: T)

fun test(){
    val biggerTitle = (3 < 2) + "positive" - "negative"
}

but you need to use some other operators like plus minus or other names and therefore its out of standard and much harder to understand!

I dont really understand why to include e.g. array def via but not ternary.

1 Like
fun <T> Boolean.thenElse(onTrue: T, onFalse: T): T = if (this) onTrue else onFalse**
fun <T> Boolean.thenElse(onTrue: () -> T, onFalse: () -> T): T = if (this) onTrue() else onFalse()

val isConditionSatisfied: Boolean = ...
val result = isConditionSatisfied.thenElse("something1", "something2")

+1 for Ternary

Ternary operator is definitely more elegant than if/else. With them you can write very readable multiline expressions like:

String value = (storeType == StoreType.Database)
        ? getDatabase().getSettingsDao().getString("my value")
        : getSettingsHelper().getSharedPreferences().getString("my value")

You just can’t write it with if/else to be nicely formatted. This is just one example I took from my head but I encounter such patterns at least few times a day.

IMHO if/else should be if/else, not ternary. It is a plus that you can assign them as expressions but only a plus. It shouldn’t forbid proper ternary operators. Maybe it’s me but It just doesn’t look nice and much harder to read. Also I always catch myself on trying to avoid if/else (ternary) at all because of that.

1 Like
String value = when(storeType == StoreType.Database){
   true -> getDatabase().getSettingsDao().getString("my value")
   false ->  getSettingsHelper().getSharedPreferences().getString("my value")
}

//misuse takeIf, but it looks more like your code
String value = takeIf{ storeType == StoreType.Database }
    ?.let{ getDatabase().getSettingsDao().getString("my value") }
    ?: getSettingsHelper().getSharedPreferences().getString("my value")

I personally use when most of the time.

2 Likes

When is more verbose and you should understand that takeIf/let/?: looks ridiculous. Understand, I’m not looking for workarounds as I can come up with lots of them myself.

I don’t understand why a lot of people support Elvis operator and are against ternary one. They essentially have the same story and very similar in implementation:

Elvis transforms
if (a != null) a else b
into
a ?: b

And ternary transforms
if (condition) a else b
into
condition ? a : b

2 Likes

As explained above (like a million times) the ? in Kotlin is an character associated with nullability. IMO this is the main reason why the ternary operator would not really fit into Kotlin. Also as explained above, the fact that if else are not statements but expressions means that the ternary operator is not needed. Yes it would be a bit shorter and some people argue even more readable, but it would not add anything new to Kotlin.

The reason why languages like Java or C++ have the ternary operator is because they can’t do stuff like

int foo = if(someCondition) 1 else 2;

They would need to write this:

int foo;
if(someCondition)
    foo = 1;
else
    foo = 2;

The fact that Kotlin treats if else as an expression and not a statement means that Kotlin basically already has a ternary operator (just with a different syntax).

I personally would support the ternary operator if not for the ?. I think it should not be used outside of the context of nullability.

As to the fact that if else is to verbose. I personally don’t like either syntax inside of a more complex expression as both tend to become to verbose in more than just the most basic examples. In those cases I just usually just declare a temp val. This is the most readable way to solve this problem IMO. And when you declare a temp val it does not matter whether you use if else or the ternary operator:

String value = (storeType == StoreType.Database)
        ? getDatabase().getSettingsDao().getString("my value")
        : getSettingsHelper().getSharedPreferences().getString("my value")

val value = if(storeType == StoreType.Database) getDatabase().getSettignsDao().getString("myValue")
else getSettingsHelper().getSharedPReferences().getString("myValue")

The only problem with this so far is the fact that the code style rules don’t really support proper alignment and indentation. But once you are used to this, not indenting the else is not even that bad (even though I would prefer it to be indented).

It is a good sign for Kotlin that this (superfluous) discussion is one of the most popular here. It seems like Kotlin doesn’t have any real problems :wink:

Is there some design document with a reasoning why the conditional operator (ternary operator is a bad name) is not included in Kotlin and never will be? This document could be linked here so that this discussion could end.

3 Likes

I’m not aware of any document regarding this. I guess there was an internal discussion at JetBrains and they decided against it. And judging from the discussion here the community is split 50/50 ( I want to say 60/40 against it, but I am biased as well).
As for the name ternary vs conditinal. One ternary describes what it is (an operator with 3 arguments) and conditional describes the function (a condition) so I guess both fit.

Here (russian) @abreslav claimed that it was not a problem to add ? to the language as part of ternary operator, but the problem was to add :, because this symbol could be useful in other new syntax (collection literals, slices, etc)

Well, that’s an interesting new slant on the matter!

I’d always thought that the sticking point would be ? rather than : .

It certainly is for me because of its association with nullability.

As regards : I suppose they could use = instead for map literals and for slices they could use the range operator .. (and its associated functions until and step) though it would be a bit verbose compared to what other languages have.

or we coulld go for

String value = (databaseType)
        T: N: getDatabase().getSettingsDao().getString("my value")
        F: getSettingsHelper().getSharedPreferences().getString("my value")

String value = (databaseType)
        T: getDatabase().getSettingsDao().getString("my value")
        F: getSettingsHelper().getSharedPreferences().getString("my value")
        N: throw UninitializedPropertyException("The databaseType is not initialized")

Two chars more and we can handle null if needed.

or change the colon in an arrow and use a colon between the types:

String value = (databaseType)
        T, N-> getDatabase().getSettingsDao().getString("my value")
        F-> getSettingsHelper().getSharedPreferences().getString("my value")

String value = (databaseType)
        T-> getDatabase().getSettingsDao().getString("my value")
        F-> getSettingsHelper().getSharedPreferences().getString("my value")
        N-> throw UninitializedPropertyException("The databaseType is not initialized")

or make it a function, so it would like more kotlin-ish, let’s call it when

String value = when(databaseType){
        T, N-> getDatabase().getSettingsDao().getString("my value")
        F-> getSettingsHelper().getSharedPreferences().getString("my value")
}

String value = when(databaseType){
        T-> getDatabase().getSettingsDao().getString("my value")
        F-> getSettingsHelper().getSharedPreferences().getString("my value")
        N-> throw UninitializedPropertyException("The databaseType is not initialized")
}

I’m just joking, about my last proposals…

18 year Java veteran here. I remember missing the ternary conditional operator when I dabbled in Scala, and I’m feeling some of the same phantom limb twinges with Kotlin.

This is a widely-used construct in other C-like languages, and for programmers coming from that background, ? strongly connotes a general conditional expression. In consideration of Kotlin’s famously null-explicit type system, it may be purer semantically to relearn it in the narrower scope of “conditions involving null”, but that means getting used to some conditional expressions having a different form than others.

J x != null ? x : other
K x ?: other // love it

J x != null ? x.foo : other
K x?.foo ?: other // still loving it

J x != null ? f(x) : other
K x?.let { f(x) } ?: other // eh, it’s better than Optional.flatMap

J test ? x : other
K if (test) x else other // this is readable, but less familiar

I suspect that the number of times I actually need to use the last form is going to go way down, but it will take a while to get used to.

4 Likes

I’ve seen too many defects introduced by the ternary operator in Java so we actually started preventing it on a new project at my last company.

We’re not so strict at my current company. Unfortunately many developers that like the ternary operator also like nesting a ternary inside another ternary which makes the code non-obvious, easy to misinterpret, and error prone. It got so bad that we added a rule that they’re not allowed to be nested and the ternary operator can only be used when it fits on a single line.

I really like that Kotlin doesn’t have the ternary operator and the if-expression is much more clear. I use this as a selling point when promoting Kotlin.

1 Like

I think the argument that ? is associated with null only is wrong. If one look from natural languages perspective everything fits into places.
We use ? in questions and its exactly ternary’s meaning. Ask and do something depending on the answer.
And we use ? to mark something questionable, about what we don’t sure. Like this:

People to come:

  • John +
  • Jane –
  • Mark - ?

Which is immaterial. The question is Kotlin, where ? is 100% associated with nullability.

And I see no profit in having that restriction.
Every programmer reuse his knowledge of natural languages, math notation, other programming languages.
Say ? will always be associated only with nulls in kotlin. But not in programmers mind.
What would be the point in supporting that made up rule?
Simpler learning? I doubt it.
What new information will you give to other person, who don’t know kotlin, when you tell him that rule? None. Just some curious fact, an anecdote.

I did not say it as a restriction but a statement of fact. ? Already is used in the Kotlin language and 100% of those uses involve nullability. In Java ? is only used as the conditional operator. Adding a non-nullable use for it leads to confusion.

Couple of other points:

Your natural language example was used to express whether Mark was going to be there. That is actually what Kotlin uses it for, to express that something may not be there (may be null).

And in natural language when we want to express 2 alternatives based on whether something is true or not we do something like, “if it is raining then drive to work else bike to work”. Note that no question marks are used to express that. It is not natural to instead write, “it is raining? drive to work: bike to work”. Kotlin lets you express it in a way that is closer to natural language, “if(itIsRaining) driveToWork() else bike to work()”.

Your argument that ? : is natural language is not supportable.

I think you considered english only :slight_smile: