Difference between safe call in Kotlin and C Sharp

Pavlo
1,643 views

Open Source Your Knowledge, Become a Contributor

Technology knowledge has to be shared and made accessible for free. Join the movement.

Create Content

Difference between safe call in Kotlin and C#

Both Kotlin and C# have safe call operation ?.. It is pretty straight forward, but these languages handle it differently in invocation chains.

Let's assume following declarations:

Kotlin:

class Foo {
    fun bar() = "bar"
}
val a: Foo? = null

C#:

class Foo
{
    public String Bar() => "bar";
}
Foo a = null;

In C# expression a?.Bar().Length is equivalent to a == null ? (int?)null : a.Bar().Length, i.e. if a equals to null then whole invocation chain will not be executed.

While in Kotlin a?.bar().length is equivalent to (if (a == null) null else a.bar()).length. And in fact this will not compile as expression a?.bar() will have String? type. a?.bar()?.length makes the job done.

C# advantages

While Kotlin behaviour feels more natural (I would expect it by default), C# allows you to be more expressive. After first .? operation in a chain you can still use usual call. It makes it easier to understand where exactly null value can be produced. For instance, in previous example a?.Bar().Length it is clear that a is expected to be null while result of Bar() is not.

Furthermore, in C# you can write a?.Bar()[0] while in Kotlin you will be forced to use explicit function call a?.bar()?.get(0). As an alternative it is possible to use let standard function a?.let { it.bar()[0] }.

Kotlin advantages

So when it can be useful to continue invocation chain even when operand of safe call operation is null?

The only case I can see is an extension function with nullable receiver type.

Let's assume following declarations:

Kotlin:

fun Int?.minusOneWhenNull() = this ?: -1

C#:

public static class IntegerExtensions
{
    public static int MinusOneWhenNull(this int? _this) => _this ?? -1;
}

Expression a?.bar()?.length.minusOneWhenNull() in Kotlin will be evaluated into -1 as expected.

While in C# a?.Bar().Length.MinusOneWhenNull() will not compile as function MinusOneWhenNull is called on expression with int type instead of int?. And even if we change receiver type of the extension function to be int, result of the expression will be null because of "short-circuit call". To solve the problem we can add brackets (a?.Bar().Length).MinusOneWhenNull() which will produce desired result -1.


Let me know down below in the comments if you know more examples where one of the behaviours will be more suitable.

Open Source Your Knowledge: become a Contributor and help others learn. Create New Content