Difference between safe call in Kotlin and C Sharp
Open Source Your Knowledge, Become a Contributor
Technology knowledge has to be shared and made accessible for free. Join the movement.
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.