Add Extension function in kotlin to all classes - kotlin

Is it possible to add extension function to all classes? I was thinking about adding it to some common base class like Object. Is it possible?

With Kotlin, Any is the super type like Object for Java.
fun Any.myExtensionFunction() {
// ...
}
And if you want to support null-receiver too:
fun Any?.myExtensionFunction() {
// ...
}

It depends on whether you want to use the type of the object in the signature (either in another argument, or in the return type). If not, use Any(?) as Kevin Robatel's answer says; but if you do, you need to use generics, e.g. (from the standard library)
inline fun <T, R> T.run(block: T.() -> R): R
inline fun <T> T.takeIf(predicate: (T) -> Boolean): T?
etc.

Related

Is it possible to use all possible types from reflection as generic type?

I am trying to use reflection to automatically create savedStateHandle for some classes.
fun <T> KProperty1<T, *>.argFrom(handle: SavedStateHandle) =
when (this.returnType.javaType) {
String::class.java -> handle.get<String>(this.name)
Int::class.java -> handle.get<Int>(this.name)
Uri::class.java -> handle.get<Uri>(this.name)
else -> throw RuntimeException("Type not implemented yet")
}
As you see IF the type is for instance String then I want the return type of get function to be String and when doing it this way I have to define every single case manually.
It would be nice if I could just do something like this.
fun <T> KProperty1<T, *>.argFrom(handle: SavedStateHandle) =
handle.get<this.returnType.javaType>(this.name)
You need a type parameter for the return type of the property. Then you can use that type parameter to specify the desired return type of get:
fun <T, V> KProperty1<T, V>.argFrom(handle: SavedStateHandle) =
handle.get<V>(this.name)

Kotlin scoping functions: Android EditText supports *apply*, *let* and *run* but not *with*

I have an Activity that holds a EditText. Imported via:
import kotlinx.android.synthetic.main.myActivity.*
I would like to use the with function but for some reason only the other scoping function are accessible:
apply, also, run, runCatching, takeIf and takeUnless are shown, but not with (and yes, I scrolled further down and even typed it out. Its marked as unknown if I do so).
To clarify, here what actually happens:
Are there rules to when an object has these functions and when not?
It is because apply, also, run, runCatching, takeIf and takeUnless are extensions, when with is function with 2 parameters. Here is good article about this.
You can use with like this:
with(editText) {
//your code
}
But you can not call with, as you tried to do this:
editText.with() //compilation error
Update:
with function purpose is to call object methods more easy, you don't need to write something like this:
someObject.a();
someObject.b();
someObject.c();
//etc
When you use with, you can write it like this:
with(someObject) {
a();
b();
c();
//etc
}
You're not getting any suggestions about with function because, it has no source type as extension, while other extensions contains source attached to it. How?
Look at the difference below :
with function
#kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
...
return receiver.block()
}
let function
#kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
...
return block(this)
}
Here T is the source type for the extension.

Generic function in Kotlin

In Kotlin you can have a generic function like this:
fun <T> singletonList(item: T): List<T> {
// ...
}
I don't understand what the purpose of the <T> after the fun keyword is for. The function returns List<T>, so what is the point of <T>?
To be able to create a generic function the compiler must know that you want to work with diferent types. Kotlin is (like Java or C#) a strongly typed language. so just passing different types into a function will make the compiler mad.
To tell the compiler that a function should be accepting multiple types you need to add a "Type Parameter"
The <T> after fun is the definition of said "Type Parameter".
Which is then used at the item Argument.
Now the compiler knows that you'll specifiy the type of item when you make the call to singletonList(item: T)
Just doing
fun singletonList(item: T) : List<T> {[...]}
would make the compiler unhappy as it does not know T.
(As long as you don't have a class named T)
You also can have multiple "Type Params" when you separate them with commas:
fun <T, U> otherFunction(firstParam: T, secondParam: U): ReturnType
This is a generic function which, as per the language's syntax requirements, needs to provide this part <T>. You can use it to specify T further:
fun <T: Number> singletonList(item: T): List<T> {
// ...
}
It's also common to have multiple generic types:
fun <T: Number, R: Any> singletonList(item: T): R {
// ...
}

Kotlin - How to create an alias function of RxJava flatmap()?

I tried to create an alias function to Flowable.flatmap() as follow, but compile error.
fun <T, R> Flowable<T>.then(mapper: Function<T, Publisher<R>>): Flowable<R> {
return flatMap(mapper)
}
The error is : One type argument expected for interface Function<out R> defined in kotlin
Have any idea? Thanks!
The flatMap takes a java.util.function.Function, the actually error is you didn't import the java.util.function.Function in your Kotlin file, but I don't suggest you use the java-8 functions because you can't take advantage of the SAM Conversions to use the lambda directly from the Kotlin code which defined with java-8 functional interface as parameter type.
You should replace Function with Function1, since the Function interface is a Kotlin marker interface only. for example:
// v--- use the `Function1<T,R>` here
fun <T, R> Flowable<T>.then(mapper: Function1<T, Publisher<R>>): Flowable<R> {
return flatMap(mapper)
}
OR use the Kotlin function type as below, for example:
// v--- use the Kotlin function type here
fun <T, R> Flowable<T>.then(mapper: (T) -> Publisher<R>): Flowable<R> {
return flatMap(mapper)
}

How to get generic param class in Kotlin?

I need to be able to tell the generic type of kotlin collection at runtime. How can I do it?
val list1 = listOf("my", "list")
val list2 = listOf(1, 2, 3)
val list3 = listOf<Double>()
/* ... */
when(list.genericType()) {
is String -> handleString(list)
is Int -> handleInt(list)
is Double -> handleDouble(list)
}
Kotlin generics share Java's characteristic of being erased at compile time, so, at run time, those lists no longer carry the necessary information to do what you're asking. The exception to this is if you write an inline function, using reified types. For example this would work:
inline fun <reified T> handleList(l: List<T>) {
when (T::class) {
Int::class -> handleInt(l)
Double::class -> handleDouble(l)
String::class -> handleString(l)
}
}
fun main() {
handleList(mutableListOf(1,2,3))
}
Inline functions get expanded at every call site, though, and mess with your stack traces, so you should use them sparingly.
Depending on what you're trying to achieve, though, there's some alternatives. You can achieve something similar at the element level with sealed classes:
sealed class ElementType {
class DoubleElement(val x: Double) : ElementType()
class StringElement(val s: String) : ElementType()
class IntElement(val i: Int) : ElementType()
}
fun handleList(l: List<ElementType>) {
l.forEach {
when (it) {
is ElementType.DoubleElement -> handleDouble(it.x)
is ElementType.StringElement -> handleString(it.s)
is ElementType.IntElement -> handleInt(it.i)
}
}
}
You can use inline functions with reified type parameters to do that:
inline fun <reified T : Any> classOfList(list: List<T>) = T::class
(runnable demo, including how to check the type in a when statement)
This solution is limited to the cases where the actual type argument for T is known at compile time, because inline functions are transformed at compile time, and the compiler substitutes their reified type parameters with the real type at each call site.
On JVM, the type arguments of generic classes are erased at runtime, and there is basically no way to retrieve them from an arbitrary List<T> (e.g. a list passed into a non-inline function as List<T> -- T is not known at compile-time for each call and is erased at runtime)
If you need more control over the reified type parameter inside the function, you might find this Q&A useful.