Is it possible to avoid code repetition when an object should return a modified copy of itself? - kotlin

I'm currently writing some classes that represent symbolic mathematical expressions. All of these are immutable.
However, I found myself often repeating the same kind of structure, so I created an interface to avoid repetition, but find myself unable to avoid duplicating the "substituteInside" method (see below), which returns a copy of the object with components corresponding to "find" replaced with "replace".
This behavior is the same for all instances of this interface.
In my current solution, the interface requires implementing a method createOp which returns the modified copy of the object.
interface UnarySymbolicOp<InType : Any,
OutType : Any,
OpType : UnarySymbolicOp<InType,OutType,OpType>> :
Symbolic<OutType> {
// Arg may be a complex expression
val arg: Symbolic<InType>
fun createOp(mesh: Symbolic<InType>) : OpType
override val variables
get() = arg.variables
override fun <V : Any> substituteInside(find: Symbolic<V>, replace: Symbolic<V>): OpType {
return createOp(arg.substitute(find, replace))
}
}
The interface can then be implemented as follows: these classes represent the operation of getting some component of an expression.
data class GetX(override val arg: Symbolic<Vector3d>) : UnarySymbolicOp<Vector3d, Double, GetX> {
override fun createOp(mesh: Symbolic<Vector3d>) = GetX(arg)
override fun eval() = arg.eval().x
}
data class GetY(override val arg: Symbolic<Vector3d>) : UnarySymbolicOp<Vector3d, Double, GetY> {
override fun createOp(mesh: Symbolic<Vector3d>) = GetY(arg)
override fun eval() = arg.eval().y
}
data class GetZ(override val arg: Symbolic<Vector3d>) : UnarySymbolicOp<Vector3d, Double, GetZ> {
override fun createOp(mesh: Symbolic<Vector3d>) = GetZ(arg)
override fun eval() = arg.eval().z
}
This improves things as other methods returning a copy of the object can use that method and thus can live in the interface, but I still have to copy this method everywhere, while it basically always does the same thing.

Related

Make class extend multiple function type interfaces with the same signature in Kotlin

I want to make a class extend multiple function type interfaces.
This works since the function types have different signatures, () -> Unit and (String) - Unit
typealias A = () -> Unit
typealias B = (something: String) -> Unit
class Test : A, B {
override fun invoke() {
TODO("Not yet implemented")
}
override fun invoke(something: String) {
TODO("Not yet implemented")
}
}
Now if I add a third function type, the compiler complains about Conflicting Overloads or A supertype appears twice
typealias A = () -> Unit
typealias B = (something: String) -> Unit
typealias C = (somethingElse: String) -> Unit
class Test : A, B, C {
override fun invoke() {
TODO("Not yet implemented")
}
override fun invoke(something: String) {
TODO("Not yet implemented")
}
override fun invoke(somethingElse: String) {
TODO("Not yet implemented")
}
}
I can obviously go and add garbage params to C to make it work, but this seems more like a hack
typealias C = (somethingElse: String, garbage: Unit?) -> Unit
but now if I define type D with the same signature,
typealias D = (somethingElseElse: String, garbage: Unit?) -> Unit
I would run into the same issue.
I thought that maybe value classes could help here:
#JvmInline
value class BString(val value: String)
#JvmInline
value class CString(val value: String)
typealias A = () -> Unit
typealias B = (something: BString) -> Unit
typealias C = (somethingElse: CString) -> Unit
class Test : A, B, C {
override fun invoke() {
TODO("Not yet implemented")
}
override fun invoke(something: BString) {
TODO("Not yet implemented")
}
override fun invoke(somethingElse: CString) {
TODO("Not yet implemented")
}
}
... but since value classes are compiled out of existence, that too is not a solution
Platform declaration clash: The following declarations have the same
JVM signature (invoke(Ljava/lang/Object;)Ljava/lang/Object;):
I'm assuming Kotlin KEEP 302, Binary Signature Name (https://github.com/Kotlin/KEEP/blob/binary-signature/proposals/multiplatform/binary-signature.md), would solve this issue in the future, but what is the correct way in the meantime to implement multiple function interfaces with the same signatures?
Practical use-case that I can think of: let's say you want to have a class that can handle Clickable and DoubleClickable, both would have something like (Event) -> Unit
EDIT: based on #mateusz's answer, this works, but only when using value classes, not if interface B and C are using normal Strings:
#JvmInline
value class BString(val value: String)
#JvmInline
value class CString(val value: String)
interface A {
operator fun invoke()
}
interface B {
operator fun invoke(something: BString)
}
interface C {
operator fun invoke(somethingElse: CString)
}
class Test : A, B, C {
override operator fun invoke() {
println("invoke A")
}
override operator fun invoke(something: BString) {
println("invoke B - something = $something")
}
override operator fun invoke(somethingElse: CString) {
println("invoke C - somethingElse = $somethingElse")
}
}
fun main(args: Array<String>) {
val handlerA = A::invoke
val handlerB = B::invoke
val handlerC = C::invoke
val t = Test()
handlerA(t)
handlerB(t, BString("hello B"))
handlerC(t, CString("hello C"))
}
outputs:
invoke A
invoke B - something = BString(value=hello B)
invoke C -somethingElse = CString(value=hello C)
The completer does not care about parameter's names.
The fun test(a: String): String and fun test(b: String): String are the same functions. When you will call test("some") then which function should be called?
You can create dedicated interfaces:
interface Clickable {
fun click(param: String)
}
interface DoubleClickable {
fun fastDoubleClick(param: String)
fun slowDoubleClick(param: String)
}
Then you can use function references if you want val handleClickFun: String -> Unit = Clickable::click
This will never work. At the fundamental JVM level, you can't implement the same interface twice with different generics. I would not expect this to ever work, even with the KEEP you mention.
Why do you want to extend function interfaces at all? If you just want the nice call syntax, you can have separate operator fun invoke overloads, without overriding anything. But even better would be using functions with actual names. If you need to pass it to methods accepting lambdas, use method references, e.g. Test::handleClick and Test::handleDoubleClick.
A typealias is just a way to give a convenient label to a specific type - it's not a type in itself, anywhere you specify that typealias, you can can just pass in a variable defined as the real type, or any other typealias you've derived from it.
So B and C are the same thing. You can have two different aliases for the same thing if that makes sense in different parts of your code (that's kinda the whole point of them! Relabel types to make them more readable or understandable) but that's just ways to refer to a type.
But when it comes to defining your class, it makes no sense. B and C are the same type, you're repeating yourself (and the compiler will give you a supertype appears twice error). And to implement that one type, you need one function - and only one, because if you have two identical functions then which one would get called?
So you can do this if you want:
typealias A = () -> Unit
typealias B = (something: String) -> Unit
typealias C = (somethingElse: String) -> Unit
class Test : A, B {
override fun invoke() {
println("invoke")
}
override fun invoke(something: String) {
println("invoke: $something")
}
}
fun doAThing(thing: C) {
thing("wow")
}
fun main() {
doAThing(Test())
}
doAThing takes a C, so we can pass it a B, because B is C.
I'm guessing that's not very useful to you, but that's the limitation of typealiases, and bare function types in general. If you want two separate functions with the exact same signature in the same scope, you need to be able to refer to them explicitly - and that usually means giving them different names.
How is your click-handler class going to handle your Event if you can't tell it whether it's a single or double-click? And even if you could (e.g. through something like (handlerFunction as B).invoke(event)) then which of your identical overridden functions in the class is which?
Like Mateusz says, you need to use interfaces, and then you can pass references to the functions, because you have a name for each one you can refer to. The things you're passing those functions into can define the types using typealiases if they want. And if you want a type that can handle both kinds of clicks, create another interface that implements both types.
If you want to be able to pass a single object that has multiple functions with the same signature, that's what you need. If you want to use function types instead, you'll have to pass the individual function references in - but something somewhere has to be able to distinguish between them in the first place, and that's usually where they're defined

Cloning object of subclass type in Kotlin

I wanted to be able to define a method to clone an object that is the same type of itself. I define the interface requesting such, but the following does not compile or run.
interface Foo {
fun <T: Foo> copy() : T
}
class Bar(private val v:Int) : Foo {
override fun copy():Bar = Bar(v)
}
main() {
val bar1 = Bar(1)
val bar2 = bar1.copy()
}
If however I write the implementing class in Java, it will compile
class Bar implements Foo {
private int v;
public Bar(int v) {this.v = v;}
public Bar copy() {
return new Bar(v);
}
}
I can rewrite the code like the following that compiles:
interface Foo<out Foo>{
fun copy(): Foo
}
class Bar(private val v:Int) : Foo<Bar> {
override fun copy(): Bar = Bar(v)
}
However the following will fail with error: no type arguments expected for fun copy(): Foo
val newF = f.copy()
fun <T: Foo> addFoo(
foo: T,
fooList: List<T>,
): MutableList<T> {
val result: MutableList<T> = arrayListOf()
for (f in fooList) {
val newF = f.copy<T>()
result.add(newF)
}
result.add(foo)
return result
}
Is there a good solution to the problem?
The problem here is that Foo doesn't know the exact type of the implementing class, so has no way to specify that its method returns that same type.
Unfortunately, Kotlin doesn't have self types (see this discussion), as they would handle this situation perfectly.
However, you can get close enough by using what C++ calls the curiously-recurring template pattern. In Kotlin (and Java) you do this by defining Foo with a type parameter explicitly extending itself (including its own type parameter):
interface Foo<T : Foo<T>> {
fun copy(): T
}
Then the implementing class can specify itself as the type argument:
class Bar(private val v: Int) : Foo<Bar> {
override fun copy(): Bar = Bar(v)
}
And because T is now the correct type, everything else works out. (In fact, the : Bar is redundant there, because it already knows what the type must be.)
Your addFoo() method will then compile with only a couple of changes: give it the same type parameter <T: Foo<T>>, and remove the (now wrong, but unnecessary) type parameter when calling f.copy(). A quick test suggests it does exactly what you want (creates a list with clones of fooList followed by foo).
Since it's often useful for a superclass or interface to refer to the implementing class, this pattern crops up quite often.
BTW, your code is easier to test if Bar has its own toString() implementation, as you can then simply print the returned list. You could make it a data class, or you could write your own, e.g.:
override fun toString() = "Bar($v)"

Kotlin class generics without duplication

Consider an abstract class:
abstract class PubSubSubscriber<T : Any>(private val topic: KClass<T>) : BackgroundFunction<PubSubMessage> {
abstract fun consume(payload: T)
override fun accept(message: PubSubMessage, context: Context) {
val json = String(Base64.getDecoder().decode(message.data.toByteArray()))
val payload = objectMapper.readValue(json, topic.java)
consume(payload)
}
}
And implementation:
class MySubscriber : PubSubSubscriber<Payload>(Payload::class) {
Is there a way to define such abstract class so that I don't have to repeat twice the Payload and Payload::class in the class definition?
Yes, with some reflection.
At construction time, we can extract the type parameter and assign it to a property that no longer needs to be given to the constructor:
abstract class PubSubSubscriber<T : Any> {
val topic: KClass<T> = extractTypeParam<T>(0).kotlin
private fun <X> extractTypeParam(paramIdx: Int): Class<X> {
require(PubSubSubscriber::class.java == javaClass.superclass) {
"PubSubSubscriber subclass $javaClass should directly extend PubSubSubscriber"
}
#Suppress("UNCHECKED_CAST")
return (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[paramIdx] as Class<X>
}
abstract fun consume(payload: T)
override fun accept(message: PubSubMessage, context: Context) {
val json = String(Base64.getDecoder().decode(message.data.toByteArray()))
val payload = objectMapper.readValue(json, topic.java)
consume(payload)
}
Note the following limitations:
A) this solution works only if MySubscriber directly extends from PubSubSubscriber. However, the given code can detect if that's not the case and warn about it (at runtime). In such cases, there are the following solutions:
MySubscriber falls back to providing a duplicate argument (essentially what you already had)
the direct superclass of MySubscriber can provide a similar detection mechanism
B) You call reflection code every time a MySubscriber instance is created. This may be too slow in certain contexts, but for many this is unproblematic.

Kotlin `object` initialization order leads to unexpected null instance

Consider the following code:
sealed class DataType<T : Any> {
abstract fun inputToType(input: String): T
abstract fun typeToSql(value: T): String
companion object {
val all = listOf(StringDt, LongDt)
}
}
object StringDt : DataType<String>() {
override fun inputToType(input: String) = input
override fun typeToSql(value: String) = "\"${value}\""
}
object LongDt : DataType<Long>() {
override fun inputToType(input: String) = input.toLong()
override fun typeToSql(value: Long) = value.toString()
}
val dataTypeList = listOfNotNull(StringDt, LongDt)
println(dataTypeList)
println(DataType.all)
Things to consider:
object as per documentation (and my understanding as well) is singleton and always instantiated
the two objects (StringDt and LongDt) are quite similar
The result of println(DataType.all) shows that one of the objects are not initialized. How is that possible? I would expect all the list elements to be initialized.
IntelliJ version: CE 2020.2
Kotlin plugin version: 1.4.0-release-IJ2020.2-1
Here's a running example which shows that the static list has a null element, while the non-static one contains both objects initialized.
It happens due to cyclical static initializations. It's pretty hard to explain this problem in two words but you can read about it here.
To fix this behavior you can change all initialization like this:
val all by lazy { listOf(StringDt, LongDt) }

When should I use delegation in Kotlin?

I have been going through multiple links (One, Two) and documentation regarding the delegate pattern and somewhat understand the advantage it brings in the form of "composition over inheritance". I can see how the inbuilt delegate properties (lazy, vetoable, map, observable) are useful; but having a hard time understanding 2 areas:
1. Why/When should I write a custom delegate for property? How is it better than overriding getter/setter of that property?
Comparing the 2 approaches:
private var withoutDelegate: String = ""
get() = DataHelper.getLatestData(::withoutDelegate.name)
set(value) {
DataHelper.setLatestData(value)
field = value
}
val withDelegate by StringDelegateProvider()
class StringDelegateProvider {
operator fun getValue(thisRef: String?, property: KProperty<*>): String {
return DataHelper.getLatestData(property.name)
}
}
2. At the class level, how is delegation better than traditional composition patterns?
Comparing the 2 approaches - composition without delegation seems much more concise:
interface Base {
fun print()
}
class BaseImpl1(val x: Int) : Base {
override fun print() { print(x) }
}
class BaseImpl2(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun clientFunctionWithDelegation() {
val i1 = BaseImpl1(10)
val i2 = BaseImpl2(10)
val b1 = Derived(i1)
val b2 = Derived(i2)
b1.print()
b2.print()
}
fun clientFunctionWithoutDelegation(){
//wihtout extending Base, we can still create multiple types of Base and use them conditionally.
val i1: Base = BaseImpl1(10)
val i2: Base = BaseImpl2(10)
i1.print()
i2.print()
}
Would appreciate if the community can share some use-cases where delegation can help.
1: You can reuse the delegate without having to override get and/or set each time. Example: the lazy delegate
2: let's say you want to create a MutableList that prints the list every time you mutate the list. You don't want to reimplement MutableList, you just want to override the functions mutating the list. So instead of manually delegating every call, you just say class PrintList<T>(original: MutableList<T>) by original and you just override the functions you care about