Nameof to get names of program elements


#1

C# has a really nice feature called nameof. With this expression you can get the name of a program element in a safe way without repeating it as a string.

Example:

fun process(customer: Customer) {
    checkArgument(customer.isTrustworthy, "customer must be trustworthy")
    ...
}

Here you have to repeat the parameter name customer in the exception message. That is error prone.

It would be nice to have a feature like nameof here:

fun process(customer: Customer) {
    checkArgument(customer.isTrustworthy, "${nameof(customer)} must be trustworthy")
    ...
}

Is something like this on the roadmap?


#2

No, we don’t have anything like that on the roadmap. Given that IntelliJ IDEA’s refactorings do a fairly good job of updating string literals, adding a special language feature just for this case seems to be a bit overkill.


#3

I disagree. String literal search may find many unrelated usages especially for common identifier names, so it couldn’t be trusted really.


#4

Absolutely agree with @ilya.gorbunov. Ruby has long had the :thing syntax which is used wildley different than “thing”.

Semantism is a core pinnacle of strongly-typed languages which Kotlin strongly firmly in. To suggest a string literal solution and leave it up to “IDE refactoring” is literally against the whole belief system which Kotlin is built upon, let alone being a huge known Magic Strings anti-pattern. This is why we have enums and the strongly-typed ‘when’ (Kotlin) / ‘switch’ (Swift) statements, to get AWAY from string-based, non-typed workarounds.

I wouldn’t expect this answer from an intermediate developer, let alone the you guys.


#5

This feature actually exists for properties and function names, but not for local variables (yet). Try this:

class Data(val namedProp: String)
fun namedFunction(): String = ""

fun main(args: Array<String>) {
    println("My property name is '${Data::namedProp.name}'")
    println("My function name is '${::namedFunction.name}'")
}

Compiler actually inlines the corresponding invocations and substitutes the actual names, so there is no runtime reflection in this code.

As for variables: https://youtrack.jetbrains.com/issue/KT-16303

P.S. There is also a minor performance problem related to existing .name support in compiler, but that is not the reason for not using this feature if you needed it, and definitely not a reason to invent any kind of nameof (because .name is the Kotlin way!): https://youtrack.jetbrains.com/issue/KT-16304


#6

Another related use case for variable names:

val `Some Kafka Topic Name` = magicallyDefine<Key, Value>("Some Kafka Topic Name")

Obviously, repeating the name is not super convenient. I could imagine, if magicallyDefine is an inline function, it could potentially access the outer variable name using similar syntax and get the String using the proposed .name semi-reflection:

val `Some Kafka Topic Name` = magicallyDefine<Key, Value>()

Where the name is deducted using syntax like val topic: String = ::return.name, which looks amazingly bad and is not always available.

I guess at this level of complexity it is much better to make a normal named class.


#7

@a.kosenkov You can achieve something like that with the delegated properties: http://kotlinlang.org/docs/reference/delegated-properties.html


#8

Another use case is to retrieve names of object properties/functions. Something like nameOf(a::foo).
I have created a feature request: https://youtrack.jetbrains.com/issue/KT-23777