I have a BaseClass and several ChildClasses. I BaseClass has a doSomething() function, which I have to override. I cannot change BaseClass or any ChildClass.
class BaseClass {
fun doSomething() {}
}
class ChildClass1 : BaseClass {}
class ChildClass2 : BaseClass {}
The overridden doSomething() function of the ChildClass have to do the same thing. So I could do this:
class MyChildClass1 : ChildClass1 {
override doSomething() {
// some tasks
}
}
class MyChildClass2 : ChildClass2 {
override doSomething() {
// same tasks as in ChildClass1
}
}
Obviously, I dont want boilerplate code. I thought about Kotlin Generics where I define on class and depending on which ChildClass I pass in, it overrides the doSomething() function.
The context is actually a little bit more complex, so I cant just pass a lambda or something like that.
Here some pseudo code, what I try to achieve:
class GenericClass : <T: BaseClass> {
override doSomething() {
// tasks ...
}
}
var genericChildClass1 = GenericClass<ChildClass1>()
Is this somehow possible in Kotlin?
Thanks!
Related
I want to ask a question that I have some clues about, but I don't want to influence the answers I will get. I have the following class hierarchy:
abstract class MyAbstractClass {
fun displayStuff(id: String) {
println("My id is $id.")
}
}
interface MyInterface {
fun displayThis() {
displayStuff("some-value")
}
fun displayStuff(id: String) // Not implemented here
}
class MyConcreteClass(): MyAbstractClass(), MyInterface {
fun doStuff() {
displayThis()
}
}
fun main() {
val result = MyConcreteClass()
result.doStuff()
result.displayStuff("id")
}
What's wrong with this design, and how do you suggest I fix it?
It would probably not be a bad idea to extract the displayStuff into another interface. Then MyAbstractClass and MyInterface can both derive from the same interface.
One overrides the displayStuff function, hence providing something like an abstract base implementation for the interface.
The other one is using the function in a specific way, thereby extending the functionality of the interface.
interface DisplayStuff {
fun displayStuff(id: String)
}
abstract class MyAbstractClass: DisplayStuff {
override fun displayStuff(id: String) = println("My id is $id.")
}
interface MyInterface : DisplayStuff {
fun displayThis() = displayStuff("some-value")
}
It is code worked in java but after convert to kotlin it does not compile.
Having a base class which has some defines as static protected member in the companion object:
abstract class ParentClass {
companion object {
#JvmField
final protected val SERVICE_TYPE_A = "the_service_type_a"
}
}
and the child class:
class ChildClass: ParentClass {
public override fun getServiceType(): String {
return SERVICE_TYPE_A. //<== got compile error
}
}
it does not compile.
how to access a parent class static protected member from subclass?
You need to use #JvmStatic instead as follows:
abstract class ParentClass {
companion object {
#JvmStatic
protected val SERVICE_TYPE_A = "the_service_type_a"
}
abstract fun getServiceType(): String
}
The final keyword in SERVICE_TYPE_A is redundant since everything is final by default in Kotlin. This also mean that if you want ParentClass to be extended, then you need to explicitly define it as open.
Then your ChildClass would look as follows:
class ChildClass: ParentClass() {
override fun getServiceType(): String {
return SERVICE_TYPE_A
}
}
For example I the following classes:
abstract class BaseClass()
class SpecificClass : BaseClass()
Now, I want to provide SpecificClass through koin dependency inject but I also want to provide the base class BaseClass in the same graph.
To be clear I want to do something like:
class Someclass {
...
private specificClass: SpecificClass by inject()
...
}
class Someclass {
...
private baseClass: BaseClass by inject()
// where this BaseClass is just the the same instace of the SpecificClass in the dependency graph
...
}
How do I do my module to do this? How can I inject the implementation instance to the baseClass reference?
You can do it using Koin in 2 ways
Methodn 1
You can create dependencies for both of them like this
single {
SpecificClass()
}
single<BaseClass> {
get<SpecificClass>()
}
In this way, whenever you inject an instance, it will get injected accordingly
Method 2
You can make use of named dependencies like this
single("BaseClassImpl") {
SpecificClass()
}
And when you want to inject it, provide key for that dependency like this:
class Someclass {
...
private specificClass: SpecificClass by inject("BaseClassImpl")
...
}
class Someclass {
...
private baseClass: BaseClass by inject("BaseClassImpl")
// where this BaseClass is just the the same instace of the SpecificClass in the dependency graph
...
}
You can't inject abstract classes.
In order to inject a class, it must be instantiable and abstract classes are not.
To inject SpecificClass with Koin you need to create a module:
val appModule = module {
single {
SpecificClass()
}
}
Initialize it in your application class:
class MyApplication : Application() {
override fun onCreate(){
super.onCreate()
// start Koin!
startKoin {
// declare used Android context
androidContext(this#MyApplication)
// declare modules
modules(appModule)
}
}
}
And use the inject delegation in your activity/fragment
class MyActivity() : AppCompatActivity() {
val specificClass : SpecificClass by inject()
}
I am confused how delegation works in Kotlin. Wikipedia says:
With language-level support for delegation, this is done implicitly by having self in the delegate refer to the original (sending) object, not the delegate (receiving object).
Given the following Code:
interface BaseInterface {
fun print()
}
open class Base() : BaseInterface {
override fun print() { println(this) }
}
class Forwarded() {
private val base = Base()
fun print() { base.print() }
}
class Inherited() : Base() {}
class Delegated(delegate: BaseInterface) : BaseInterface by delegate
fun main(args: Array<String>) {
print("Forwarded: ")
Forwarded().print();
print("Inherited: ")
Inherited().print();
print("Delegated: ")
Delegated(Base()).print();
}
I get this output:
Forwarded: Base#7440e464
Inherited: Inherited#49476842
Delegated: Base#78308db1
I'd expect Delegated to return Delegated because self/this should refer to the original object. Do I get it wrong or is Kotlins delegation different?
Kotlin delegation is very simple - it generates all interface methods and implicitly invokes it on delegated object, except for methods explicitly overriden by the user.
Your example is functionally the same as:
class Delegated(delegate: BaseInterface) : BaseInterface{
// when generating bytecode kotlin assigns delegate object to internal final variable
// that is not visible at compile time
private val d = delegate
override fun print(){
d.print()
}
}
So it's pretty clear why it prints Base.
I think this is easiest to understand if we look at the decompiled Java bytecode this gets compiled into:
You can do this by going to Tools > Kotlin > Show Kotlin Bytecode and then clicking Decompile
public final class Delegated implements BaseInterface {
// $FF: synthetic field
private final BaseInterface $$delegate_0;
public Delegated(#NotNull BaseInterface delegate) {
Intrinsics.checkParameterIsNotNull(delegate, "delegate");
super();
this.$$delegate_0 = delegate;
}
public void print() {
this.$$delegate_0.print();
}
}
So when you do interface delegation what happens is that Kotlin creates field for the delegate named $$delegate_0 and adds methods in your delegating class which will operate on $$delegate_0. You can have multiple delegates as well, they will get their own fields. There is one caveat though: you can't access $$delegate_0 directly, not even if you make it a var like this:
class Delegated(var delegate: BaseInterface) : BaseInterface by delegate
This will compile to:
public final class Delegated implements BaseInterface {
#NotNull
private BaseInterface delegate;
// $FF: synthetic field
private final BaseInterface $$delegate_0;
#NotNull
public final BaseInterface getDelegate() {
return this.delegate;
}
public final void setDelegate(#NotNull BaseInterface var1) {
Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
this.delegate = var1;
}
public Delegated(#NotNull BaseInterface delegate) {
Intrinsics.checkParameterIsNotNull(delegate, "delegate");
super();
this.$$delegate_0 = delegate;
this.delegate = delegate;
}
public void print() {
this.$$delegate_0.print();
}
}
sadly. I've written about this topic here.
Hi I would like know why the following example doesn't work
abstract class BaseClass {
}
class ConcretClasOne : BaseCalculator {
}
class ConcretClasTwo : BaseCalculator {
}
abstract class BaseRun {
abstract fun run(param: BaseClass): Int
}
class ConcretRun : BaseRun {
override fun run(param: ConcretClasOne): Int {
return 0
}
}
this shows me a message run overrides nothing.
I suppose that kotlin isn't able to match the abstract class and the concrete implementation, but what other alternative is there to emulate this behavior, that the run method in the concrete class ConcretRun should receive a concrete param ConcretClasOne?
Generics
Using generics, you can make the base class have a type extending the base class, so that the run method can take that type in.
abstract class BaseClass {
}
class ConcretClasOne: BaseCalculator {
}
class ConcretClasTwo: BaseCalculator {
}
abstract class BaseRun<T: BaseClass> {
abstract fun run(param: T): Int
}
class ConcretRun: BaseRun<ConcretClasOne> {
override fun run(param: ConcretClasOne): Int {
return 0
}
}
Why your code doesn't work
At the moment you are trying to override a method with a more specific type, but as the more general base method can accept more types the more specific method cannot override it.