Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin extension method as alias for long method name?

I am working in Kotlin using a Kotlin-native library object containing a method whose .nameIsMuchTooLongAndIsStillNotClear. In a manner similar to typealias, I want to create an alias to the method, so I can refer to it as something .shortAndClear. To complicate matters slightly, these functions have several parameters, many of which have defaults that I'd prefer not to pre-process in a wrapper. After further research, it still seems like an extension function is the way to go.

To use an example function that's easy to test, let's say I want to create an alias-type extension for String.startsWith that is called String.beg. I can easily get the following solution to work:

inline fun String.beg(prefix: CharSequence, ignoreCase: Boolean = false) = startsWith(prefix, ignoreCase)   // works ok

However, this seems to require that I list all argument and their defaults, and do so for every overload. (The real method signatures in question are considerably longer with many more defaults.) In the spirit of "don't repeat yourself", is there a way I can use a function reference to String::startsWith so that I don't have to enumerate all arguments? I've tried several forms, but none of them work:

// none of these work:
fun String.beg = String::startsWith
fun String.beg = this::startsWith
val String.beg: (CharSequence, Boolean) -> Boolean = String::startsWith
like image 934
sirksel Avatar asked Oct 08 '17 12:10

sirksel


Video Answer


1 Answers

Currently there's no way to fully achieve what you are trying to do. If you want to keep your default parameters, you have to do (as you said):

fun String.beg(prefix: CharSequence, ignoreCase: Boolean = false) = startsWith(prefix, ignoreCase)
// Or if you know that ignoreCase will be always false, you can pass the value directly to "startsWith()
fun String.beg(prefix: CharSequence) = startsWith(prefix, false)

Instead, if you haven't default parameters or you don't care if you have to pass the default value when you will invoke the function, you can use a function reference.

val String.beg: (CharSequence, Boolean) -> Boolean get() = this::startsWith
// If the parameters can be inferred, you can avoid the type specification.
// In this case it won't compile because there are several combinations for "startsWith()".
val String.beg get() = this::startsWith

In this case, you can't specify the default value of a parameter because beg is a lambda.

Since Kotlin 1.2 (currently in beta), you can avoid to specify this on a function reference. Same examples written above but in Kotlin 1.2:

val String.beg: (CharSequence, Boolean) -> Boolean get() = ::startsWith
// If the parameters can be inferred, you can avoid the type specification.
// In this case it won't compile because there are several combinations for "startsWith()".
val String.beg get() = ::startsWith
like image 55
Giorgio Antonioli Avatar answered Oct 21 '22 03:10

Giorgio Antonioli