I've got a question about safe call operator behav...
# compiler
k
I've got a question about safe call operator behavior (
.?
) in Kotlin vs the similar operator in C#. Say we have such classes
Copy code
data class Head(val name: String)
    data class Department(val head: Head)
    data class Employee(val department: Department)
and the variable
e
of type
Employee?
. Kotlin will refuse to compile an expression
e?.department.head.name
complaining that
head
property cannot be accessed on an instance of
Department?
type. So this expression needs to be rewritten as
e?.department?.head?.name
, which in my opinion looks a bit clumsy cause we know in advance that the only thing in this chain that can possibly be null is
e
. In C#, on the other hand, this operator discards the whole chain if null is encountered, compiling
e?.Department.Head.Name
to
(e != null) ? e.Department.Head.Name : null
. Am I missing something or does C# really do a better job in this case? Is this difference in behavior due to the fact that it was hard or impossible to to implement a C#-like behavior given null-aware type system? Or maybe there are some other cases when this Kotlin compiler behavior allows for safer code and therefore is desired? Would like to hear the community as well as JetBrains folks' thoughts on this.
d
There is may be an extension property on nullable
Department
, so call without
?
may be resolved to it
Copy code
class Employee(val department: Department)
class Department {
    val name: String = "Member"
}
val Department?.name: String get() = "Extension"

fun test(e: Employee?) {
    e?.department?.name // Member
    e?.department.name // Extenstion
}
Without required safe call in second line of test will be ambiguity between member and extension If force to resolve it to member then there will be no pretty way to call an extension If force resolve to extension then adding an extension somewhere in your codebase may change resolve somewhere else (and it's unpredicatable process)
k
Makes sense, thanks! By the way, are such extension methods shadowing members of the method receiver somewhat idiomatic in Kotlin? To me such extension method looks rather exotic and maybe even a code smell (making call site look like it deals with non-nullable type, therefore deceiving the code reader).
d
Extension never shadows member, so it's safe (and useless) write code like
Copy code
class A(val x: Int)
val A.x: String get() = ""
Declaring extension with same as member name but on nullable receiver useful when you have some nullable field and default value for it, but you don't want to write that value to object for some reason
👍 1