Method References to Super Class Method - kotlin

How to use method references to refer to super class methods?
In Java 8 you can do SubClass.super::method.
What would be the syntax in Kotlin?
Looking forward to your response!
Conclusion
Thanks to Bernard Rocha!
The syntax is SubClass::method.
But be careful. In my case the subclass was a generic class. Don't forget to declare it as those:
MySubMap<K, V>::method.
EDIT
It still doesn't work in Kotlin.
Hers's an example in Java 8 of a method reference to a super class method:
public abstract class SuperClass {
void method() {
System.out.println("superclass method()");
}
}
public class SubClass extends SuperClass {
#Override
void method() {
Runnable superMethodL = () -> super.method();
Runnable superMethodMR = SubClass.super::method;
}
}
I'm still not able to do the same in Kotlin...
EDIT
This is an example how I tried to achieve it in Kotlin:
open class Bar {
open fun getString(): String = "Hello"
}
class Foo : Bar() {
fun testFunction(action: () -> String): String = action()
override fun getString(): String {
//this will throw an StackOverflow error, since it will continuously call 'Foo.getString()'
return testFunction(this::getString)
}
}
I want to have something like that:
...
override fun getString(): String {
//this should call 'Bar.getString' only once. No StackOverflow error should happen.
return testFunction(super::getString)
}
...
Conclusion
It's not possible to do so in Kotlin yet.
I submitted a feature report. It can be found here: KT-21103 Method Reference to Super Class Method

As the documentation says you use it like in java:
If we need to use a member of a class, or an extension function, it
needs to be qualified. e.g. String::toCharArray gives us an extension
function for type String: String.() -> CharArray.
EDIT
I think you can achieve what you want doing something like this:
open class SuperClass {
companion object {
fun getMyString(): String {
return "Hello"
}
}
}
class SubClass : SuperClass() {
fun getMyAwesomeString(): String {
val reference = SuperClass.Companion
return testFunction(reference::getMyString)
}
private fun testFunction(s: KFunction0<String>): String {
return s.invoke()
}
}

Don't know if it is possible to get the reference to super class's function, but here is an alternative to what you want to achieve:
override fun getString(): String = testFunction { super.getString() }

According to Bernardo's answer, you might have something like this. It doesn't have remarkable changes.
fun methodInActivity() {
runOnUiThread(this::config)
}
fun config(){
}
What is more, in the incoming 1.2 version you can use just
::config

Related

Kotlin: use generic on interface level as argument type for function

Is it impossible to use generic on interface level as argument type for function?
I read about out and in keywords but as I understand they don't work for this case.
interface BaseB
open class ChildB1: BaseB
open class ChildB2: BaseB
abstract class BaseMapper<V: BaseB> {
open fun test(v: V) {
return
}
}
class TestMapper1: BaseMapper<ChildB1>() {
override fun test(v: ChildB1) {
return
}
}
class TestMapper2: BaseMapper<ChildB2>() {
override fun test(v: ChildB2) {
return
}
}
#Test
fun t() {
//ERROR
val mappers: List<BaseMapper<BaseB>> = listOf(TestMapper1(), TestMapper2())
mappers[0].test(ChildB1())
}
A BaseMapper<ChildB1> is not logically a BaseMapper<BaseB>. It consumes ChildB’s, so if you passed some other implementation of Base it would cause a ClassCastException if the compiler let you do that. There is no common subtype of your two subclasses besides Nothing, so the only way to put both of these types in the same list is to make it a List<BaseMapper<in Nothing>>.
Example of why it is not logically a BaseMapper<BaseB>:
open class ChildB1: BaseB {
fun sayHello() = println("Hello world")
}
class TestMapper1: BaseMapper<ChildB1>() {
override fun test(v: ChildB1) {
v.sayHello() // if v is not a ChildB1, this would be impossible
}
}
//...
val impossibleCast: BaseMapper<BaseB> = TestMapper1()
// TestMapper1 cannot call sayHello() because it's undefined for ChildB2.
// This is impossible:
impossibleCast.test(ChildB2())
// ...so the compiler prevents you from doing the impossible cast in the first place.

Allow function calls only in special context

I'm trying to write a class that only allows certain methods to be called in a lambda of one function.
Basically, I want to achieve similar behaviour to how you can only call suspend functions in a suspend context.
Right now the closest I can get is this.
class MyClass {
fun runCommands(block: CommandContext.() -> Unit) {
// do prep work
block.invoke(commandContext)
// do cleanup work
}
val commandContext = CommandContext()
inner class CommandContext {
fun commandFunc() {} // only callable from the lambda
}
}
The issues I'm having with this is I can't make CommandContext private so you could always make your own instance and run the command externally. It is also unnecessary for it to be instantiatable but I can't make an "inner object."
Any ideas on how to do this cleaner?
Outer scope should know that there is a commandFunc() method in CommandContext class (and that this class actually exists). That's why it can't be private. But you can encapsulate its implementation, effectively making it private, keeping public only its interface:
interface CommandContext {
fun commandFunc()
}
class MyClass {
fun runCommands(block: CommandContext.() -> Unit) {
// do prep work
block.invoke(CommandContextImpl)
// do cleanup work
}
private object CommandContextImpl : CommandContext {
override fun commandFunc() {} //actual implementation
}
}
//Usage:
fun main() {
MyClass().runCommands { commandFunc() }
}

Static Instance of Interface as part of the interface

Imagine I had an interface like:
interface MyInterface {
fun doSomething()
}
And I was interop-ing between Kotlin and Java. I now want a constant static instance of this interface but I want that to be part of the interface. I could do this:
interface MyInterface {
fun doSomething()
companion object {
val CONSTANT = object: MyInterface {
override fun doSomething() { ... }
}
}
}
but that means I need to write MyInterface.Companion.getCONSTANT(). #JvmField doesn't work here.
I've also tried:
interface MyInterface {
fun doSomething()
object CONSTANT: MyInterface {
override fun doSomething() { ... }
}
}
}
Which works in other Kotlin files (I can write MyInterface.CONSTANT) but I'd have to write MyInterface.CONSTANT.INSTANCE in Java. This solution seems the closest to what I want.
Any solutions? I want to be able to write MyInterface.CONSTANT in both Kotlin and Java and have them refer to a single static final object that implements the interface.
I believe I could also convert my Interface to an abstract class but that's the last resort.
The issue of not being able to use #JvmStatic in interfaces is tracked in this ticket: https://youtrack.jetbrains.com/oauth?state=%2Fissue%2FKT-6301
It is fixed by now and one comment says
Fix would be avaliable in 1.2.30 under '-language-version 1.3' option

Create an annotation instance in Kotlin

I have a framework written in Java that, using reflection, get the fields on an annotation and make some decisions based on them. At some point I am also able to create an ad-hoc instance of the annotation and set the fields myself. This part looks something like this:
public #interface ThirdPartyAnnotation{
String foo();
}
class MyApp{
ThirdPartyAnnotation getInstanceOfAnnotation(final String foo)
{
ThirdPartyAnnotation annotation = new ThirdPartyAnnotation()
{
#Override
public String foo()
{
return foo;
}
};
return annotation;
}
}
Now I am trying to do the exact thing in Kotlin. Bear in mind that the annotation is in a third party jar.
Anyway, here is how I tried it in Kotlin:
class MyApp{
fun getAnnotationInstance(fooString:String):ThirdPartyAnnotation{
return ThirdPartyAnnotation(){
override fun foo=fooString
}
}
But the compiler complains about: Annotation class cannot be instantiated
So the question is: how should I do this in Kotlin?
You can do this with Kotlin reflection:
val annotation = ThirdPartyAnnotation::class.constructors.first().call("fooValue")
In the case of annotation having no-arg constructor (e.g. each annotation field has a default value), you can use following approach:
annotation class SomeAnnotation(
val someField: Boolean = false,
)
val annotation = SomeAnnotation::class.createInstance()
This is the solution I might have found but feels like a hack to me and I would prefer to be able to solve it within the language.
Anyway, for what is worth,it goes like this:
class MyApp {
fun getInstanceOfAnnotation(foo: String): ThirdPartyAnnotation {
val annotationListener = object : InvocationHandler {
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
return when (method?.name) {
"foo" -> foo
else -> FindBy::class.java
}
}
}
return Proxy.newProxyInstance(ThirdPartyAnnotation::class.java.classLoader, arrayOf(ThirdPartyAnnotation::class.java), annotationListener) as ThirdPartyAnnotation
}
}

How to specify "own type" as return type in Kotlin

Is there a way to specify the return type of a function to be the type of the called object?
e.g.
trait Foo {
fun bar(): <??> /* what to put here? */ {
return this
}
}
class FooClassA : Foo {
fun a() {}
}
class FooClassB : Foo {
fun b() {}
}
// this is the desired effect:
val a = FooClassA().bar() // should be of type FooClassA
a.a() // so this would work
val b = FooClassB().bar() // should be of type FooClassB
b.b() // so this would work
In effect, this would be roughly equivalent to instancetype in Objective-C or Self in Swift.
There's no language feature supporting this, but you can always use recursive generics (which is the pattern many libraries use):
// Define a recursive generic parameter Me
trait Foo<Me: Foo<Me>> {
fun bar(): Me {
// Here we have to cast, because the compiler does not know that Me is the same as this class
return this as Me
}
}
// In subclasses, pass itself to the superclass as an argument:
class FooClassA : Foo<FooClassA> {
fun a() {}
}
class FooClassB : Foo<FooClassB> {
fun b() {}
}
You can return something's own type with extension functions.
interface ExampleInterface
// Everything that implements ExampleInterface will have this method.
fun <T : ExampleInterface> T.doSomething(): T {
return this
}
class ClassA : ExampleInterface {
fun classASpecificMethod() {}
}
class ClassB : ExampleInterface {
fun classBSpecificMethod() {}
}
fun example() {
// doSomething() returns ClassA!
ClassA().doSomething().classASpecificMethod()
// doSomething() returns ClassB!
ClassB().doSomething().classBSpecificMethod()
}
You can use an extension method to achieve the "returns same type" effect. Here's a quick example that shows a base type with multiple type parameters and an extension method that takes a function which operates on an instance of said type:
public abstract class BuilderBase<A, B> {}
public fun <B : BuilderBase<*, *>> B.doIt(): B {
// Do something
return this
}
public class MyBuilder : BuilderBase<Int,String>() {}
public fun demo() {
val b : MyBuilder = MyBuilder().doIt()
}
Since extension methods are resolved statically (at least as of M12), you may need to have the extension delegate the actual implementation to its this should you need type-specific behaviors.
Recursive Type Bound
The pattern you have shown in the question is known as recursive type bound in the JVM world. A recursive type is one that includes a function that uses that type itself as a type for its parameter or its return value. In your example, you are using the same type for the return value by saying return this.
Example
Let's understand this with a simple and real example. We'll replace trait from your example with interface because trait is now deprecated in Kotlin. In this example, the interface VitaminSource returns different implementations of the sources of different vitamins.
In the following interface, you can see that its type parameter has itself as an upper bound. This is why it's known as recursive type bound:
VitaminSource.kt
interface VitaminSource<T: VitaminSource<T>> {
fun getSource(): T {
#Suppress("UNCHECKED_CAST")
return this as T
}
}
We suppress the UNCHECKED_CAST warning because the compiler can't possibly know whether we passed the same class name as a type argument.
Then we extend the interface with concrete implementations:
Carrot.kt
class Carrot : VitaminSource<Carrot> {
fun getVitaminA() = println("Vitamin A")
}
Banana.kt
class Banana : VitaminSource<Banana> {
fun getVitaminB() = println("Vitamin B")
}
While extending the classes, you must make sure to pass the same class to the interface otherwise you'll get ClassCastException at runtime:
class Banana : VitaminSource<Banana> // OK
class Banana : VitaminSource<Carrot> // No compiler error but exception at runtime
Test.kt
fun main() {
val carrot = Carrot().getSource()
carrot.getVitaminA()
val banana = Banana().getSource()
banana.getVitaminB()
}
That's it! Hope that helps.
Depending on the exact use case, scope functions can be a good alternative. For the builder pattern apply seems to be most useful because the context object is this and the result of the scope function is this as well.
Consider this example for a builder of List with a specialized builder subclass:
open class ListBuilder<E> {
// Return type does not matter, could also use Unit and not return anything
// But might be good to avoid that to not force users to use scope functions
fun add(element: E): ListBuilder<E> {
...
return this
}
fun buildList(): List<E> {
...
}
}
class EnhancedListBuilder<E>: ListBuilder<E>() {
fun addTwice(element: E): EnhancedListBuilder<E> {
addNTimes(element, 2)
return this
}
fun addNTimes(element: E, times: Int): EnhancedListBuilder<E> {
repeat(times) {
add(element)
}
return this
}
}
// Usage of builder:
val list = EnhancedListBuilder<String>().apply {
add("a") // Note: This would return only ListBuilder
addTwice("b")
addNTimes("c", 3)
}.buildList()
However, this only works if all methods have this as result. If one of the methods actually creates a new instance, then that instance would be discarded.
This is based on this answer to a similar question.
You can do it also via extension functions.
class Foo
fun <T: Foo>T.someFun(): T {
return this
}
Foo().someFun().someFun()