I really like using default implementations for interfaces in Kotlin, especially for common patterns like Observable. Here's my interface,
interface Observable<T>{
// How do I cache this?
val observers: MutableList<Observer<T>>
get() = LinkedList<>()
fun addObserver(o:Observer<T>){
observers.add(o)
}
fun removeObserver(o:Observer<T>){
observers.remove(o)
}
fun notifyObservers(u:T){
for (o in observers){
o.update(u)
}
}
}
The interface refers to a list of observers, but the get() call is returning a new LinkedList() each time. How can I cache the value of observers so that it's only created once? I've tried using kotlin-lazy, but either can't get the syntax right, or it's not meant for interfaces. My IDE complains "Delegated properties are not allowed in interfaces."
UPDATE
Based on Yoav's answer, I've change my interface to
interface Observable<T>{
val observers: MutableList<Observer<T>>
}
And then in the implementing class,
class MyObservable : Observable<String>
private val _observers = LinkedList<Observer<String>>()
override val observers: MutableList<Observer<String>>
get() = _observers
Any tips to make this more succinct?
According to Kotlin docs:
Interfaces in Kotlin are very similar to Java 8. They can contain
declarations of abstract methods, as well as method implementations.
What makes them different from abstract classes is that interfaces
cannot store state.
Interface can't hold any state as they are fully abstract. Perhaps you should use an abstract class in order to cache the values?
See this question for more information about the reason for interfaces being stateless.
An interface is a contract specifying what its implementer promises to
be able to do. It does not need to specify state because state is an
implementation detail and only serves to constrain implementers in how
this contract is fulfilled. If you want to specify state you might
want to rethink you use of interfaces and look at abstract base
classes instead.
While you cannot create stateful variables on an interface directly, you can achieve the same result by defining a companion object containing a cache and do a dynamic lookup on this. Using your example:
interface Observable<T>{
// How do I cache this?
val observers: MutableList<Observer<T>>
get() = cache.computeIfAbsent(this) { mutableListOf<Observer<T>>() } as MutableList<Observer<T>>
fun addObserver(o:Observer<T>){
observers.add(o)
}
fun removeObserver(o:Observer<T>){
observers.remove(o)
}
fun notifyObservers(u:T){
for (o in observers){
o.update(u)
}
}
companion object {
val cache = WeakHashMap<Observable<*>, MutableList<*>>()
}
}
If you want a more efficient cache, you can use a library like Caffeine.
After thinking about this some more, I discovered a nice pattern. First I tried the direct approach:
interface A {
val prop = compute() // Nope: Property initializers are not allowed in interfaces
/*...*/
}
As you mentioned, it can be done using a custom accessor but must be recomputed each time:
interface A {
val prop get() = compute() // OK, but recomputed each time someProperty is read
/*...*/
}
Then I thought, perhaps we can use a delegated property instead? But this is not allowed either:
interface A {
val prop by { compute() } // Not allowed: Delegated properties are not allowed in interfaces
/*...*/
}
Finally, I found you can achieve the same result by creating a property extension with a delegate:
interface A { /*...*/ }
val A.prop by lazy { compute() }
From a usage standpoint, you just import the extension and can access a.prop as usual.
Related
I am exploring and actively using generics in production with Kotlin.
Kotlin + generics is a big puzzle for me, so maybe you can explain and help me understand how it works here, compared to Java.
I have class AbstracApiClient (not really abstract)
class AbstracApiClient {
open protected fun makeRequest(requestBuilder: AbstractRequestBuilder) {
// ...
}
}
AbstractRequestBuilder (not really abstract):
open class AbstractRequestBuilder {
...
}
ConcreteApiClient that inherits AbstractApiClient that should override makeRequest with ConcreteRequestBuilder inherited from AbstractRequestBuilder:
class ConcreteApiClient: AbstractApiClient() {
protected override fun makeRequest(requestBuilder: ConcreteRequestBuilder) {
// ...
}
}
class ConcreteRequestBuilder: AbstractRequestBuilder()
As I would have more concrete API clients. I would like to make an abstraction that I can pass inherited concrete requests builders and override `make requests method.
I tried using it as it is but wouldn't work
I tried this notation protected open fun <R: ApiRequestBuilder> make request(request builder: R) but it won't match overriding function which I want it to be: protected override fun make request(request builder: ConcreteRequestBuilder)
What other options do I have? Am I missing something here?
Note: I cannot use interface or abstract classes in this scenario, so ideally I would like to find a way with inheritance and functions overriding.
You can't override a method with more specific argument types, because it breaks Liskov's substitution principle:
val client: AbstractApiClient = ConcreteApiClient()
client.makeRequest(AbstractRequestBuilder())
As you can see above, the ConreteApiClient implementation has to be able to handle all possible inputs of the parent class, because it could be accessed through the parent class's API.
To do what you want, you need to restrict the parent class itself via generics:
open class AbstractApiClient<R : AbstractRequestBuilder> {
open protected fun makeRequest(requestBuilder: R) {
// ...
}
}
class ConcreteApiClient: AbstractApiClient<ConcreteRequestBuilder>() {
protected override fun makeRequest(requestBuilder: ConcreteRequestBuilder) {
// ...
}
}
This way, any instance of AbstractApiClient<R> has to show which type of request builder it accepts (in the type argument). It prevents the above issue because now the parent type also carries information:
// doesn't compile
val client: AbstractApiClient<AbstractRequestBuilder> = ConcreteApiClient()
// this compiles
val client: AbstractApiClient<ConcreteRequestBuilder> = ConcreteApiClient()
I tried this notation protected open fun <R: ApiRequestBuilder> make request(request builder: R)
Now regarding this attempt, it doesn't work because if you make the method generic (not the class) it means every implementation of the method has to handle all kinds of R (NOT one R per implementation). Putting the generic on the class allows to specify the generic argument once per instance of the class.
I have an interface Persistable which looks like this, the <T extends Statement<T>> List<Statement<T>> is to allow it to support both BoundedStatements and SimpleStatements in data stax 4.x driver.
public interface Persistable {
<T extends Statement<T>> List<Statement<T>> statements();
}
This java interface is inherited by Kotlin class A such that
data class UpdateRule(
private val something: S) : Persistable {
override fun statements(): List<Statement<BoundStatement> {
return PutKeyValue(Function(orgId, serviceId), JsonUtil.toJson(rule)).statements() //this returns BoundStatement
}
}
However, this gives the error Conflicting overloads.This code seems to work in Java(although with a warning), but in Kotlin it does not allow at all, how can I resolve this while also making sure parent interface remains generic to both Bound and Simple Statement?
You seem to misunderstand what the generics in Persistable mean. As it is written right now, you are supposed to implement the statements method so that it can handle any kind of T that extends Statement<T>. The generics there doesn't mean "implement this by choosing a kind of statement that you like".
It only produces a warning in Java because Java's generics is broken. Because of type erasure, List<Statement<BoundStatement> and List<Statement<T>> both erase to the same type - List, so the method in UpdateRule does implement the method in the interface if you consider the erasures. OTOH, type erasure isn't a thing in Kotlin (at least not in Kotlin/Core).
To fix this, you can move the generic type parameter to the interface:
public interface Persistable<T extends Statement<T>> {
List<Statement<T>> statements();
}
data class UpdateRule(private val something: S) :
Persistable<BoundStatement> {
override fun statements(): List<BoundStatement> =
PutKeyValue(Function(orgId, serviceId), JsonUtil.toJson(rule)).statements()
}
Notice how when we are implementing the interface, we can now specify the specific T that we are implementing for.
In Java just like in Kotin, the value of the type parameter of a generic method is determined by the caller of the method, and can be different at every call of the method, even on the same instance.
In your specific case, with the Java interface declared like this, statements() is supposed to be implemented in such a way that the caller can choose which type of statement will be returned by a given call to this method. This is not the case in your implementation, and that's why Kotlin doesn't allow it. As pointed out by #Sweeper, Java is broken in this respect and might let you get away with a warning.
This is different when using a generic class or interface. If you define the type parameter at the class/interface level, then the value of that type parameter is determined at construction time of the class, or can be fixed by subclasses. For a given instance, all calls to the method will return a well known type, which is (I believe) what you want here.
You can do this in Java:
public interface Persistable<T extends Statement<T>> {
List<Statement<T>> statements();
}
And then in Kotlin:
data class UpdateRule(
private val something: S
) : Persistable<BoundStatement> {
override fun statements(): List<BoundStatement> {
return PutKeyValue(Function(orgId, serviceId), JsonUtil.toJson(rule)).statements() //this returns BoundStatement
}
}
I am working on a library that has a few interfaces that are related to each other.
Main example is ViewModel<M: Model, W: Widget>. Then we have an interface for Model and interface for Widget.
The widget interface has a method that takes in a ViewModel object and then uses it to configure itself.
abstract fun configure(viewModel: ViewModel<M: Model, W: Widget>)
I am looking for a way to make that method require the subclass implementation of ViewModel, instead of just the interface.
So a ContainerWidget would need this method: fun configure(viewModel: ContainerViewModel)
The library I am emulating is using Swift and does this with their associated type keyword, which says you can tell us the type later.
Does anyone know an option like that for Kotlin?
Thanks a lot for the help.
abstract class WLViewModel<DataModel : WLDataModel, WidgetType : WLWidget>(val dataModel: DataModel) {
abstract fun configure(view: WidgetType)
}
interface WLWidget {
var viewModel: WLViewModel<WLDataModel, WLWidget>
fun <M, O : WLDataModel, T : WLWidget> configure(viewModel: M) where M : WLViewModel<O, T>
}
interface WLDataModel
fun WLWidget.create(viewModel: WLViewModel<WLDataModel, WLWidget>) {
configure(viewModel)
}
I don't think there's a good way, I'm afraid.
The traditional Java approach fudges it by using recursive type parameters. You could give your WLWidget interface a type parameter of the actual subclass, like WLWidget<T : WLWidget<T>>, and then make all the knock-on changes. But that's ugly and doesn't handle all cases. (See these other questions for more info.)
There have been discussions about adding self types to Kotlin, which would probably be a better match for your case, but they're not here yet.
i have a question about kotlin:
Imagine you have this:
sealed class Graph : Serializable
data class Graph1() : Graph() {}
data class Graph2() : Graph() {}
And you want to have a factory class that given a subtype of Graph gives you a GraphView.
So, you have something similar to
interface GraphViewFactory{
fun get(data: Graph1):GraphView
fun get(data: Graph2):GraphView
}
And also you have the implementation for that.
Is possible in kotlin avoid this method explosion of interface having one per graphtype using inline and reified? I'm trying to but i'm not being able.
On the one hand, kotlin interface (I think) does not allow inline functions, on the other hand even without the interface i'm not able to auto cast parameter T as reified to one of the specific subtype class inside the factory class.
You wouldn't have to keep creating methods (though you may want to depending on how complex it is to create a GraphView), but the number of cases in your when will grow.
class GraphViewFactory {
fun get(data: Graph): GraphView {
return when {
is Graph1 -> TODO()
is Graph2 -> TODO()
else -> IllegalArgumentException()
}
}
}
Using reified types doesn't buy you anything here.
Suppose I have a very intricate specification defined as an interface:
interface Spec {
fun sayHello()
}
And a standard implementation:
class Impl(private val msg: String) : Spec {
override fun sayHello() {
println(msg)
}
}
Now suppose that I want to create a class that implements this specification and delegates to an implementation, but the exact delegate object is mutable throughout the object's lifetime. Here's an example:
class Derived(var target: Spec) : Spec by target
The problem with the above example is that the constructor argument target is set as the delegate object when the constructor is called. The delegate is then accessed by the class directly instead of performing a property access. (This has been confirmed by looking through the bytecode produced by Kotlin.)
So, even if the property target is modified after the class is constructed, the delegate does not change.
Can anybody provide a method for performing this delegation in Kotlin without having to write out every single method?
An ideal solution would also allow for delegation to something as general as a lambda or other expression that would be evaluated and used as the delegate whenever the delegate is needed throughout the lifetime of the object.
Right now there is no way to do that. See Kotlin issue KT-5870
Currenlty Kotlin evaluates expression for delegate in class initializer
You can add a level of indirection:
class Holder(var impl: Spec) : Spec {
override fun sayHello() = impl.sayHello()
}
class Derived(target: Spec,
private val holder: Holder = Holder(target)) : Spec by holder {
fun changeTarget(newTarget: Spec) {
holder.impl = newTarget
}
}
Unfortunately holder must be a constructor parameter in order to be used with the delegation construct (as for Kotlin v1.0), so it complicates the primary constructor.