Why does `first` not return nullable?

Why does first not return a nullable value?

val impossible: String = listOf("a", "bb", "ccc").first { it.length > 10 }

Since it is not known at compile time whether the predicate returns true or false, first should return a nullable value, in this case String?.

And why does this method even exist? It’s more or less the same as fun <T> Array<out T>.find(predicate: (T) -> Boolean): T? but has an unsafe return type.

Probably, it’s for the cases when you are quite confident that there will be at least one matching item. For other ones there is firstOrNull function.

The return type is safe since this function will throw if there is no first. As @h0tk3y points out, the function you’re probably looking for is firstOrNull().

I wouldn’t call throwing exceptions safe, otherwise we wouldn’t need the null-safety, but could rely on the “safe” NullPointerExceptions :wink:

But I wonder why there are find and firstOrNull (with predicate), what is pretty much the same.

It is statically safe. The signature of your method is accurate: if your method returns something, it will be a T, not a T?.

Actually the method has two return types T or NoSuchElementException. And this is pretty much the same “safety” as returning T or null. Since exception handling is not forced at compile time, methods that could throw exceptions are not safe, or more precise they are not “compile time safe”. I think thats the main reason why Rust doesn’t have exceptions.

3 Likes

But I wonder why there are find and firstOrNull (with predicate), what is pretty much the same.

They are not pretty much the same thing, they are exactly the same thing. See the source code:

    public inline fun <T> Iterable<T>.find(predicate: (T) -> Boolean): T? {
        return firstOrNull(predicate)
    }

They are both synonyms, but since find is inline there is no real runtime cost to having both.

As to why, see this from the Kotlin Bog talking about upcoming changes in M13 and M14:

find vs firstOrNull
There were many debates about naming a function that finds the first element matching given predicate in a collection. find is easy to explore, but firstOrNull is consistent with how this operation is called in LINQ and Reactive Extensions. Prior to M13 find was deprecated in favor of firstOrNull, but now we’ve decided to “undeprecate” it and leave as a synonym for firstOrNull. Also we’ve provided findLast, which is a synonym for lastOrNull.

1 Like

[quote=“medium, post:1, topic:1465, full:true”]
Why does first not return a nullable value?

val impossible: String = listOf("a", "bb", "ccc").first { it.length > 10 }

Since it is not known at compile time whether the predicate returns true or false, first should return a nullable value, in this case String?.[/quote]

One esoteric reason is that collections can contain nulls and the thing you are searching for could theoretcially be null.

val impossible: String? = listOf("a", null, "ccc").first { it == null }

Is the value null because there was no null found or because it found the null.

I grant that this code has no real purpose except in the way first is implemented now as a check to verify the list had a null.

There are valid reasons to throw an exception when looking for something and valid reasons to just return a nullable. It is a very good thing that Kotlin doesn’t force one or the other and gives you the choice.

Thanks for the explanation, even though I totally disagree with the reasoning behind keeping both methods. I think it is a very poor reason for unnecessary redundancy to keep methods because some popular frameworks use certain method names. Tomorrow other frameworks will be popular … With this reasoning the standard lib could be completely polluted!

I fear that it’s too late now, but would strongly vote for removing the one or the other.

And as that excerpt said they had “many debates” on the subject and as they said they started down the path of choosing one or the other. If you start with the premise that first which throws an exception should exist (which you incorrectly argued against) the question is which do you choose, find or firstOrNull? Either choice would inevitably cause confusion. If you go with find the someone who uses first would wonder why there was no version of first that returns nullable instead of throwing an exception. If you go with firstOrNull people are going to wonder why there is no find function as they likely will not think to look for firstOrNull.

The answer is a compromise to keep the redundacy, but since either choice will result in the same bytecode being generated it is zero cost redundancy. And no this does not mean they intend to copy all function names from all frameworks.

2 Likes

Having this thread show up in Google results might confuse more people than having two methods that are easily understandable and documented. And you have to handle the case of collection with Nullable values no matter which approach you take. There are only a few cases in StdLib where things like this feel more redundant than others, it isn’t wide-spread, and it isn’t propagating, if anything it has reduced over time. But now, post 1.0 it would not make sense to remove it and let it play out until some pre-2.0 where after more study it could be deprecated. And that study, based on statistical use, would say more than this thread here by far. You are one opinion and there are many conflicting opinions and the decision can be made based on real usage instead of opinions later.

1 Like