Is there a way to get the type of object that inherits an interface (or another class) in Kotlin? - kotlin

I've got an interface IMyInterface with a method
fun myMethod(thing: T){}
I also have a class
class MyClass : IMyInterface{}
What I want is that when I implement the members of the interface it automatically sets the type T to be MyClass. Is there a way of doing that?
So, instead of writing
interface IMyInterface <T>{
fun myMethod(thing: T){}
}
class MyClass: IMyInterface<MyClass>{
override fun myMethod(thing: MyClass){} // <<<-- the type is set because I explicitly set it above
}
I want to have something like this:
interface IMyInterface{
fun myMethod(thing: T){}
}
class MyClass: IMyInterface{
override fun myMethod(thing: MyClass){} // <<<-- the template type <T> of the interface is resolved by the compiler by checking what type I provided in method signature (
}
Or maybe getting a type of the class implementing an abstract class.

What you are wanting to do is not possible. You want the compiler to "Magically" figure out what the template parameter is... think about it; how would it know - there is a potentially infinite subset of IMyInterface. It is not implied in your interface that the template type <T> is even of type IMyInterface, so it could literally be any type...
Here is another angle on the problem that may make it clear why the compiler cannot do this:
// The same interface as your example, but with extra method
interface IMyInterface{
fun myMethod(thing: T){}
fun myOtherMethod(thing: T){}
}
// The same implementation as before, except the extra method is overridden with a different type than the first method
class MyClass: IMyInterface{
// the template type <T> of the interface is resolved by the compiler by
// checking what type I provided in method signature (this is what you want compiler to do)
override fun myMethod(thing: MyClass){}
// Uh oh! How does the copmpiler resolve this? We just figured out that <T> was my class.
// So this method won't compile... why not just tell entire class what <T> is
// rather than trying to make all method signatures match up so the compiler can "infer" the type???
override fun myOtherMethod(thing: MyOtherClass) {}
}
class MyOtherClass : IMyInterface {
override fun myMethod(thing: MyOtherClass) = this
override fun myOtherMethod(thing: MyOtherClass) = this
}

There is another problem which Thomas Cook's answer doesn't cover: even if this was possible, you run into major problems with subtyping in at least two ways.
Let's assume a keyword Self which means what you want and
interface IMyInterface{
fun myMethod(thing: Self): Unit
}
Problem 1: You have a val x: IMyInterface = ... What can you pass to x.myMethod? Certainly not any IMyInterface, that would defeat the purpose. But the only thing which is guaranteed to have the same concrete type as x is... x (assuming no Self-returning methods).
Problem 2: Add class MySubClass : MyClass. It must have override fun myMethod(thing: MySubClass), right? But it also has to inherit override fun myMethod(thing: MyClass) from MyClass.

Related

Why is the no lateinit block in Kotlin?

The following code is valid Kotlin code:
abstract class A {
protected lateinit var v: X
abstract fun f(): X
class SubA : A() {
override fun f(): X {
return SubX()
}
init {
v = f()
}
}
}
It defines an abstract class which has a lateinit var field and an abstract method that sets the value of that field. The reason behind this is that that method may be called later again, and its behavior should be defined in the subclasses that extend the original class.
This code is a simplification of a real-world code, and even though it works, I feel like it is messy since the developer of the subclass could choose not to (or forget) to call v = f() inside an init block. And we cannot do that in A either because then it will show a warning that we are calling a non-final method in the constructor. What I propose is the following:
abstract class A {
private lateinit var v: X
abstract fun f(): X
class SubA : A() {
override fun f(): X {
return SubX()
}
}
lateinit { // this does not exist
v = f()
}
}
The benefits of this is that now the field can be private instead of protected, and the developer does not have to manually call v = f() in each of their subclasses (or the subclasses of their subclasses), and the naming fits with the nomenclature of Kotlin since lateinit is already a keyword and init is already a block. The only difference between an init and a lateinit block would be that the contents of a lateinit block are executed after the subclass constructors, not before like init.
My question is, why isn't this a thing? Is this already possible with some other syntax that I do not know about? If not, do you think it's something that should be added to Kotlin? How and where can I make this suggestion so that the developers would most likely see it?
There are three options, and you can implement your lateinit block in two ways
don't lazy init - just have a normal construction parameter
use a delegated lazy property
add a lambda construction parameter to the superclass class A
All of these solves the problem of requiring subclasses of A having to perform some initialization task. The behaviour is encapsulated within class A.
Normal construction parameter
Normally I'd prefer this approach, and don't lazy init. It's usually not needed.
abstract class A(val v: X)
class SubA : A(SubX())
interface X
class SubX : X
fun f() can be replaced entirely by val v.
This has many advantages, primarily that it's easier to understand, manage because it's immutable, and update as your application changes.
Delegated lazy property
Assuming lazy initialization is required, and based on the example you've provided, I prefer the delegated lazy property approach.
The existing equivalent of your proposed lateinit block is a lazy property.
abstract class A {
protected val v: X by lazy { f() }
abstract fun f(): X
}
class SubA : A() {
override fun f(): X {
return SubX()
}
}
interface X
class SubX : X
The superclass can simply call the function f() from within the lazy {} block.
The lazy block will only run once, if it is required.
Construction parameter
Alternatively the superclass can define a lambda as construction parameter, which returns an X.
Using a lambda as a construction parameter might be preferred if the providers are independent of implementations of class A, so they can be defined separately, which helps with testing and re-used.
fun interface ValueProvider : () -> X
abstract class A(
private val valueProvider: ValueProvider
) {
protected val v: X get() = valueProvider()
}
class SubA : A(ValueProvider { SubX() })
interface X
class SubX : X
The construction parameter replaces the need for fun f().
To make things crystal clear I've also defined the lambda as ValueProvider. This also makes it easier to find usages, and to define some KDoc on it.
For some variety, I haven't used a lazy delegate here. Because val v has a getter defined (get() = ...), valueProvider will always be invoked. But, if needed, a lazy property can be used again.
abstract class A(
private val valueProvider: ValueProvider
) {
protected val v: X by lazy(valueProvider)
}

Can I resolve a generic type from another generic declaration in an interface?

Expect you have an interface like this:
interface MyInterface<T : BaseClass<I>, I> {
fun someMethod(param: I) : T
}
As you can see I use I as a parameter in someMethod. But actually I don't want to declare I when I implement this interface like this:
class BaseClassImpl : BaseClass<OtherClass>
class Impl : MyInterface<BaseClassImpl, OtherClass> {
override fun someMethod(param: OtherClass) {
TODO("Not yet implemented")
}
}
Theoretically it should be possible that the I generic can be resolved by the compiler without the additional declaration because it's provided by BaseClassImpl. So MyInterface<BaseClassImpl> should already provide enough information to resolve the necessary generic for someMethod().
Is there any way to achieve that in Kotlin?
It's impossile in Kotlin.
Language specification states:
There are two kinds of type inference supported by Kotlin.
Local type inference, for inferring types of expressions locally, in statement/expression scope;
Function signature type inference, for inferring types of function return values and/or parameters.
It can't infer type of one generic parameter based on the type of another (especially for supertype declaration, because it is a very base for building type constrains system).
You may declare typealiases (for each T) to avoid repating I each time you implement this interface:
typealias MyInterfaceForBaseClassImpl = MyInterface<BaseClassImpl, OtherClass>
class Impl : MyInterfaceForBaseClassImpl {
override fun someMethod(param: OtherClass) : BaseClassImpl {
//...
}
}
It is not about compiler resolving, but about enforcing, when you declare interface MyInterface<T : BaseClass<I>, I : OtherClass> , declaration expects two parameters, May be you can create OtherInterface with OtherClass embedded and use it while implementing instead of MyInterface
interface BaseClass<I: OtherClass>
interface OtherClass
interface MyInterface<I : OtherClass, T: BaseClass<I>> {
fun someMethod(param: I)
}
class BaseClassImpl: BaseClass<OtherClass>
interface OtherInterface<T: BaseClass<OtherClass>> : MyInterface<OtherClass, T>
class Impl : OtherInterface<BaseClassImpl> {
override fun someMethod(param: OtherClass) {
}
}

Make a function execute only in Kotlin interfaces?

If I have an interface, is there any easy way I can declare a function to make it a public member, but non-overridable? Meaning, it would be exclusively callable and could not be set or overridden by its descendants
interface IFoo {
fun ExecuteOnly(){
// Do Something
}
}
I read a book recently by CommonsWare where this situation was described.
and I quote it from there:
"... As a result, anything in an interface hierarchy is permanently open , until you start
implementing the interfaces in classes. If that is a problem — if you have some
function that you really want to mark as final — use abstract classes, not interfaces..."
You can define an extension function on the interface.
fun IFoo.executeOnly() {
}
It will still be possible for someone to define a member function with that name in a class implementing IFoo but the intention is quite clear. And anyway when using an object via a IFoo reference the IFoo extension will be chosen.
No, you cannot. That's not how Kotlin's interface is implemented.
You can use an abstract class instead
abstract class Foo {
fun executeOnly(){
// Do Something
}
}
Ofcourse You Can... Actually there is not much difference bw kotlin interfaces and abstract classes... simply add a body and a private modifier..
interface MyInterface {
fun triggerTakeMe(){
takeMe()
}
private fun takeMe(){
println("Taken")
}
}
class MyClass : MyInterface
fun main() {
val obj = MyClass()
obj.triggerTakeMe()
}

Instantiating classes from non-reified type parameters

I'm building an ORM for use with jasync-sql in Kotlin and there's a fundamental problem that I can't solve. I think it boils down to:
How can one instantiate an instance of a class of type T, given a
non-reified type parameter T?
The well known Spring Data project manages this and you can see it in their CrudRepository<T, ID> interface that is parameterised with a type parameter T and exposes methods that return instances of type T. I've had a look through the source without much success but somewhere it must be able to instantiate a class of type T at runtime, despite the fact that T is being erased.
When I look at my own AbstractRepository<T> abstract class, I can't work out how to get a reference to the constructor of T as it requires accessing T::class.constructors which understandably fails unless T is a reified type. Given that one can only used reified types in the parameters of inline functions, I'm a bit lost as to how this can work?
On the JVM, runtime types of objects are erased, but generic types on classes aren't. So if you're working with concrete specializations, you can use reflection to retrieve the type parameter:
import java.lang.reflect.*
​
abstract class AbstractRepository<T>
​
#Suppress("UNCHECKED_CAST")
fun <T> Class<out AbstractRepository<T>>.repositoryType(): Class<T> =
generateSequence<Type>(this) {
(it as? Class<*> ?: (it as? ParameterizedType)?.rawType as? Class<*>)
?.genericSuperclass
}
.filterIsInstance<ParameterizedType>()
.first { it.rawType == AbstractRepository::class.java }
.actualTypeArguments
.single() as Class<T>
​
class IntRepository : AbstractRepository<Int>()
class StringRepository : AbstractRepository<String>()
interface Foo
class FooRepository : AbstractRepository<Foo>()
class Bar
class BarRepository : AbstractRepository<Bar>()
​
fun main() {
println(IntRepository::class.java.repositoryType())
println(StringRepository::class.java.repositoryType())
println(FooRepository::class.java.repositoryType())
println(BarRepository::class.java.repositoryType())
}
class java.lang.Integer
class java.lang.String
interface Foo
class Bar
In your own CrudRepository you can add a companion object with an inline fun which is responsible to instantiate your repository by passing to it the corresponding class.
class MyCrudRepository<T> protected constructor(
private val type: Class<T>,
) {
companion object {
inline fun <reified T : Any> of() = MyCrudRepository(T::class.java)
}
fun createTypeInstance() = type::class.createInstance()
}

Getting class of lateinit property in Kotlin

Is it somehow possible to get ::class.java from Kotlin lateinit property before it is initialized?
Logically it should work - I'm trying to obtain a class not a value, but in reality it fails with uninitialized property access exception.
Note that the property I'm trying to get class of is in generic class and its type is one of generic parameters:
abstract class MVIFragment<
out INTERACTOR : MVIInteractor<UINTERFACE>,
UINTERFACE : MVIUIInterface,
MODEL : MVIViewModel
>
: Fragment(), MVIUIInterface, KodeinAware {
lateinit var viewModel: MODEL
I need the class to create an instance of ViewModel
viewModel = ViewModelProviders.of(this).get(viewModel::class.java)
Of course I can't do:
viewModel = ViewModelProviders.of(this).get(MODEL::class.java)
Any solution for that?
Due to type erasure, generic types are not known at runtime. That's just how Java/JVM works, and Kotlin doesn't attempt to magically work around it. (Unlike Scala, which has implicit magic which works magically, except when it doesn't.)
You will have to pass it along from some context where the type is statically determined, e.g.
class Container<T : Any>(private val tClass: Class<T>) {
val t: T = tClass.newInstance()
}
Container(String::class.java)
You can use an inline function with reified types to hide this ugliness,
class Container<T : Any>(private val tClass: Class<T>) {
val t: T = tClass.newInstance()
companion object {
inline operator fun <reified T : Any> invoke() = Container(T::class.java)
}
}
Container<String>()
which really compiles to the same thing. (The <String> can be omitted if type inference can determine it from context.)
In your case, it won't be possible to do this trick in the base (abstract) class; it has to be done on the concrete types.