Could a class delegate an interface to multiple implementations with a few lines? Given this interface:
interface Foo {
fun doA()
fun doB()
}
The following class would compile for a single delegate:
class FooImpl(delegate: Foo): Foo by delegate
Although useless, it generates java bytecode for what is should do: delegate Foo -> Foo.
Could this be possible for a list of delegates as well? Such that it delegates Foo -> List<Foo>. Like:
class FooImpl(delegates: List<Foo>): Foo by delegates
Right now, our codebase is filled with classes such as:
class FooImpl(private val delegates: List<Foo>): Foo {
override fun doA() { delegates.forEach { it.doA() }
override fun doB() { delegates.forEach { it.doB() }
}
It feels like busy work and it's unnecessarily error prone, plus it creates unneeded work for the dev writing the code and the dev reviewing the code. I'm aware it can become complex for return values, but that will never be the case. In the current code, there's always a set of an interface, 2 actual implementations and a root implementation filled with doA() { delegates.forEach { it.doA() } .
Could this be simplified using Kotlin?
Related
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)
}
I've created a View and I encountered a problem with my interface for Buttons ClickListener.
Interface looks like this
interface CustomButtonsClickListener : () -> Unit {
fun onPlusClick(view: View, button: ImageButton)
fun onMinusClick(view: View, button: ImageButton)
}
It is implemented by the method:
fun setCustomButtonsClickListeners(clickListener: CustomButtonsClickListener) {
binding.addButton.setOnClickListener {
clickListener.onPlusClick(this, binding.addButton)
}
binding.minusButton.setOnClickListener {
clickListener.onMinusClick(this, binding.minusButton)
}
}
This is how it look like "outside"
view.setCustomButtonsClickListeners(object : CustomButtonsClickListener {
override fun onPlusClick(view: View, button: ImageButton) {
}
override fun onMinusClick(view: View, button: ImageButton) {
}
})
The Problem:
I am getting error on object saying:
Object is not abstract and does not implement abstract member public abstract fun invoke()...
What is the method invoke() and how should I implement it? I would rather do it inside the View class so I don't have to do it while using the View somewhere in the app.
This looks like confusion over syntax. The line:
interface CustomButtonsClickListener : () -> Unit {
creates an interface which extends () -> Unit (and goes on to add two methods to it).
() -> Unit is the type of a function which takes no parameters and returns nothing useful. You don't often need to know that function's name (as the lambda syntax hides it), but this is one of those corner cases where you find out that it's called… invoke()!
(It's described in the documentation.)
So you're defining an interface with three methods: one inherited from the parent interface, and the other two declared here.
So of course, when you try to implement the interface but implement only two of those three methods, the compiler complains that you've forgotten the third.
I guess you just want an interface with only your two new methods, so you can simply declare it with:
interface CustomButtonsClickListener {
I have an abstract class that implements DefaultLifecycleObserver. I'd like to call lifecycle.addObserver(this) from the init block, but it says "Leaking 'this' in constructor of non-final class MyAbstractClass".
My code:
abstract class MyAbstractClass(protected val activity: AppCompatActivity) : DefaultLifecycleObserver {
init {
activity.lifecycle.addObserver(this)
}
.
.
.
}
I can move this line of code to the init block of each final class that extends this abstract class, but I don't like the idea, especially because I want to guarantee that each new class that will extend MyAbstractClass in the future will call it as well.
Is there a better place to call this without creating a leak?
I suppose you could post your call so it only happens after the object is fully instantiated:
abstract class MyAbstractClass(protected val activity: AppCompatActivity) : DefaultLifecycleObserver {
init {
Handler(Looper.getMainLooper()).post {
activity.lifecycle.addObserver(this)
}
}
}
Or it might be less surprising to create an extension function you can tack onto your constructor calls. Then you can explicitly start the observation immediately. You'd have to make activity public, though. By defining it in an extension like this, your subclasses can call this and return themselves so you can chain it to constructor calls.
fun <T: MyAbstractClass> T.alsoBegin(): T {
activity.lifecycle.addObserver(this)
return this
}
val foo = SomeImplementation(myActivity).alsoBegin()
How to force immediate instantiation of enum values?
By default, in Kotlin enums are instantiated on first access (like objects/singletons), i.e., the following minimal example
class Foo
fun create(msg: String) = Foo().also { println("$msg") }
enum class A(val foo: Foo) {
ONE(create("1")),
TWO(create("2"))
}
enum class B(val foo: Foo) {
THREE(create("3")),
FOUR(create("4"))
}
fun main() {
println("main")
println(A.ONE)
}
outputs:
main
1
2
ONE
Is it possible to force the enums to be instantiated directly/statically before main, such that the output is as follows?
1
2
3
4
main
ONE
Sure, I could just put something like val ignore = listOf(A.ONE, B.THREE) somewhere, but I'd like to avoid such manual repetition.
Maybe there's a way using some existing annotation, or creating a new one, or something else? :)
JVM loads classes only on first access. This is not only for kotlin but also for Java. For Java we have ways to initialize a class before main, for instance, static initializer block, or Class.forName. Similarly you can use the static initializer block in Kotlin.
object Temp {
init {
A.ONE
}
#JvmStatic fun main(args: Array<String>) {
println("main")
println(A.ONE)
}
}
Kotlin enables me to implement an interface by delegating to a primary constructor argument like so:
class Foo(xs : ArrayList<Int>) : List<Int> by xs { }
But this exhibits the backing implementer to the user. Delegating to an anonymous also seems to be ok:
class Foo() : List<Int> by ArrayList<Int>() { }
This hides the implementation details, but we loose access to features not provided by the interface, which in this case is mutability.
I would therefore like to delegate the implementation to a property that is not in the primary constructor. What I would like to have is similar to
class Foo() : List<Int> by xs {
val xs : List<Int> = ArrayList<Int>()
}
which doesn't compile.
Is it possible to have a property defined explicitly in the class body and still be able to delegate implementation to it?
This is not currently possible. The expression in the by-clause is computed only once before the construction of the class, so you cannot reference symbols of that class.
There is a request in the issue tracker to allow this, although it's almost definitely not going to be supported in Kotlin 1.0.
One funny workaround that sometimes works is to make the property which you want to be a delegate, a constructor parameter with the default value instead. That way it'll be accessible both in the by-clause and in the class body:
class Foo(val xs: List<Int> = ArrayList<Int>()) : List<Int> by xs {
fun bar() {
println(xs)
}
}
Keep in mind though that xs in by xs is still calculated only once here, so even if xs is a var property, only the default value provided in the constructor will be used. It's not a universal solution, but sometimes it can help.
Expanding on the answer of Alexander Udalov, I came up with a solution using a private base class
private open class FooBase(protected val xs : MutableList<Int>) : List<Int> by xs { }
class Foo() : FooBase(ArrayList()) {
fun bar() {
xs.add(5)
}
}
Now I can have access to the property backing my interface implementation but am not restricted to operations provided by that interface while still hiding the actual implementation from the user.
Note: Although it works, I get the following warning from IntelliJ IDEA 15 CE which arises from EXPOSED_SUPER_CLASS inspection: Deprecated: subclass effective visibility 'public' should be the same or less permissive than its superclass effective visibility 'private'. I'm not quite sure what the deprecated part here means – whether the warning will be removed in the future or this won't compile at some point. Anyway, we don't really have to use a private open class, abstract or simply open will do, because even if the user is allowed to create an instance of FooBase, there is not much he can do with it.
Update:
There is actualy a simple and compact solution that does not use any suspicious behaviour:
class Foo private constructor(private val xs: ArrayList<Int>) : List<Int> by xs {
constructor() : this(ArrayList<Int>()) { }
}