Generic Interface inheritance - kotlin

I have a set of component interfaces
interface ITest<I> {
operator fun invoke(p: I)
}
interface OTest<O> {
operator fun invoke(): O
}
interface IOTest<I, O> {
operator fun invoke(p: I): O
}
and a corresponding functional interface
interface TestAdder<T> {
fun add_f(p: T) {} //default impl
}
that gets inherited to add the components from above to respective (functional) collection interfaces
interface ITestSet<I> : TestAdder<ITest<I>> {
val i_v: I
fun i_f1(p: I) {} // default impl
fun i_f2(p: I) {} // default impl
fun i_f3(p: I) {} // default impl
}
interface OTestSet<O> : TestAdder<OTest<O>> {
val o_v: O
fun o_f1(p: O) {} // default impl
fun o_f2(p: O) {} // default impl
fun o_f3(p: O) {} // default impl
}
interface IOTestSet<I, O> : TestAdder<IOTest<I, O>> {
val i_v: I
val o_v: O
// same as ITestSet<I>
fun i_f1(p: I) {} // default impl
fun i_f2(p: I) {} // default impl
fun i_f3(p: I) {} // default impl
// same as OTestSet<O>
fun o_f1(p: O) {} // default impl
fun o_f2(p: O) {} // default impl
fun o_f3(p: O) {} // default impl
fun io_f1(p: I): O
...
}
So far, so unnecessay: ideally IOTestSet<I, O> should inherit the functionality defined in ITestSet<I> and OTestSet<O>:
interface IOTestSet<I, O> : ITestSet<I>, OTestSet<O>, TestAdder<IOTest<I, O>> {
fun io_f1(p: I): O
...
}
but obviously the TestAdder<T> interface introduces inconsistency within the inheritance chain.
This smells like an age-old, archetypal paradigm (and probably even an XY) problem, still it seems I have to ask:
Q: How to compose this inheritance chain?
Or what is the established/much better/less and not unnecessarily convoluted/more elegant design pattern?

As for why this doesn't work, it is because you are inheriting from the same interface, just with different type arguments. And the reason why you can't do that is explained here.
Composition
When inheritance doesn't work, we can try composition. (See also: "Prefer Composition Over Inheritance")
Rather than having ITestSet and OTestSet inherit TestAdder, which is the root cause of your "inheriting from the same interface but with different type arguments" problem, add get-only properties of type TestAdder to ITestSet, OTestSet, as well as IOTestSet.
Then IOTestSet will be able to inherit ITestSet and OTestSet. The full code is as below:
// I have added variance modifiers where appropriate
interface ITest<in I> {
operator fun invoke(p: I)
}
interface OTest<out O> {
operator fun invoke(): O
}
interface IOTest<in I, out O> {
operator fun invoke(p: I): O
}
interface TestAdder<in T> {
fun add_f(p: T) {} //default impl
}
interface ITestSet<I> {
val i_v: I
val inputAdder: TestAdder<ITest<I>>
fun i_f1(p: I) {} // default impl
fun i_f2(p: I) {} // default impl
fun i_f3(p: I) {} // default impl
}
interface OTestSet<O> : TestAdder<OTest<O>> {
val o_v: O
val outputAdder: TestAdder<OTest<O>>
fun o_f1(p: O) {} // default impl
fun o_f2(p: O) {} // default impl
fun o_f3(p: O) {} // default impl
}
interface IOTestSet<I, O> : ITestSet<I>, OTestSet<O> {
val ioAdder: TestAdder<IOTest<I, O>>
fun io_f1(p: I): O
}
Implementing the interfaces
From what I can see, you can still implement this new set of interfaces in the same way as you did before - e.g. to implement ITestSet<String>, you just do:
class Foo: ITestSet<String> {
override val i_v: String = "Some String"
override val inputAdder = object: TestAdder<ITest<String>> {
// implementation goes here...
}
}
Note that it is possible to provide a default implementation for inputAdder:
interface ITestSet<I> {
val i_v: I
val inputAdder: TestAdder<ITest<I>> get() = object: TestAdder<ITest<I>> {
// implement your thing here...
}
...
}
but this recreates the object every time you access inputAdder, which may not be the semantics you intended.
This brings me to another difference of this design, compared to your original design: you allow implementations to implement inputAdder, outputAdder, and ioAdder in whatever way they like. This means that they are not necessarily implemented so that e.g. each ITestSet always has the same inputAdder, like in your original design, where the "inputAdder" of each ITestSet is always itself. Of course, this isn't a problem if you have total control over the code.

Related

How to use functional types or lambdas as type for Kotlin's context receivers?

package yamin
typealias Foo = () -> Unit
fun main() {
bar {
baz()
}
}
fun bar(foo: Foo) {
foo()
}
context(Foo)
fun baz() {
//
}
I tried to use a lambda type for the context of a function, which seems to be fine at this point but when I tried to call that function in that context, or at least what I think is that context I'm failing, and Kotlin's compiler is showing me this error for baz():
No required context receiver found: Cxt { context((yamin.Foo /* = () -> kotlin.Unit */)) public fun baz(): kotlin.Unit defined in yamin in file Main.kt[SimpleFunctionDescriptorImpl#7b5e305f] }
Maybe I misunderstood Kotlin's context receivers or I'm expecting something that it's not designed for. I just want to create a function that can only be called in certain context and in this example only in a certain lambda.
As it is right now, your baz can be called like this:
val someFoo: Foo = {}
with(someFoo) {
baz()
}
By using with, I bring an instance of () -> Unit into the context, so someFoo becomes a context receiver with which I can call baz. In baz, I can then access this someFoo by using this#Foo. This is how context receivers are supposed to work.
If you want baz to only be able to be called in bar's lambda, bar's lambda needs to provide the context receiver using a receiver parameter, similar to how with's lambda is declared T.() -> R.
object Foo
fun main() {
bar {
baz()
}
}
fun bar(foo: Foo.() -> Unit) {
Foo.foo()
}
context(Foo)
fun baz() {
// ...
}
I changed the actual context here to just an object, because as far as I can see, there is nothing special about bar's lambda. Of course, if you want, you can make it provide extra information to baz by changing Foo to a class that does contain data.
Note that this does not prevent someone from doing:
with(Foo) {
baz()
}
It is quite hard to prevent against this without adding another layer outside of bar, like:
// note that bar is no longer a global function
import bar.Foo.Companion.bar
class Foo private constructor() {
companion object {
fun bar(foo: Foo.() -> Unit) {
Foo().foo()
}
}
}
context(Foo)
fun baz() {
// ...
}
You can also do something simple like this prevents it from happening from outside the package:
sealed interface FooInterface
private object Foo: FooInterface
fun bar(foo: FooInterface.() -> Unit) {
Foo.foo()
}
context(FooInterface)
fun baz() {
// ...
}
To make a function that can only be called in a certain scope, give the function itself a receiver. Instead of typealias Foo = () -> Unit, you would use something like typealias Foo = MyReceiver.() -> Unit.
You can do this with a regular extension receiver, but it's also possible with context receivers.
Here's a simple version that works for me:
typealias Foo = BarScope.() -> Unit
fun main() {
bar {
baz()
}
}
object BarScope
fun bar(foo: Foo) {
BarScope.foo()
}
context(BarScope)
fun baz() {
}

Kotlin: use generic on interface level as argument type for function

Is it impossible to use generic on interface level as argument type for function?
I read about out and in keywords but as I understand they don't work for this case.
interface BaseB
open class ChildB1: BaseB
open class ChildB2: BaseB
abstract class BaseMapper<V: BaseB> {
open fun test(v: V) {
return
}
}
class TestMapper1: BaseMapper<ChildB1>() {
override fun test(v: ChildB1) {
return
}
}
class TestMapper2: BaseMapper<ChildB2>() {
override fun test(v: ChildB2) {
return
}
}
#Test
fun t() {
//ERROR
val mappers: List<BaseMapper<BaseB>> = listOf(TestMapper1(), TestMapper2())
mappers[0].test(ChildB1())
}
A BaseMapper<ChildB1> is not logically a BaseMapper<BaseB>. It consumes ChildB’s, so if you passed some other implementation of Base it would cause a ClassCastException if the compiler let you do that. There is no common subtype of your two subclasses besides Nothing, so the only way to put both of these types in the same list is to make it a List<BaseMapper<in Nothing>>.
Example of why it is not logically a BaseMapper<BaseB>:
open class ChildB1: BaseB {
fun sayHello() = println("Hello world")
}
class TestMapper1: BaseMapper<ChildB1>() {
override fun test(v: ChildB1) {
v.sayHello() // if v is not a ChildB1, this would be impossible
}
}
//...
val impossibleCast: BaseMapper<BaseB> = TestMapper1()
// TestMapper1 cannot call sayHello() because it's undefined for ChildB2.
// This is impossible:
impossibleCast.test(ChildB2())
// ...so the compiler prevents you from doing the impossible cast in the first place.

Generics in Objects

I have a question about sealed class, generics and object.
Let's say I would like to model something like 3 finite cases with a sealed class something like this:
sealed class ChangeState<S> {
fun reduceState(state: S): S
}
data class SetState<S>(val newState: S) : ChangeState<S>() {
override fun reduce(state: S): S = newState
}
object NoStateChange : ChangeState<Nothing>() { // What do I specify here for ChangeState? Nothing?
override fun reduce(state: Nothing): Nothing {
throw Exception("This should never be called")
}
}
The goal is to provide a convenient way to define NoStateChange in a generic way that it can be used as following:
fun foo(i : Int) : ChangeState<Int> {
return if (i==0)
NoStateChange // Won't compile because return type is ChangeState<Nothing> but expected ChangeState<Int>
else
SetState(i)
}
Is there a way to do that with object and Generics somehow?
As pointed out by #Tenfour04 the issue is that out is needed but reduceState() would require in as well. However, reduceState() can be refactored out of the class hierarchy and moved to an extension function like that:
sealed class ChangeState<out S>
data class SetState<S>(val newState: S) : ChangeState<S>()
object NoStateChange : ChangeState<Nothing>()
fun <S> ChangeState<S>.reduce(state: S): S {
return when (val change = this) {
is SetState -> change.newState
is NoStateChange -> state
}
}

Can I omit interface methods which I do not use in Kotlin?

What if I am only interested in onSee and do not care for other events? Can I at least omit the methods that have no return values?
interface EventHandler
{
fun onSee()
fun onHear()
fun onSmell()
fun onTouch()
fun onAwake()
fun onSleep()
}
fun addEventHandler(handler:EventHandler)
{
}
fun Main()
{
addEventHandler(object:EventHandler
{
override fun onSee()
{
print("I see.")
}
})
}
Sure, that is possible! you can implement one interface method when you extend it, all you have to do is to provide a default implementation for the other methods in the interface declaration
interface EventHandler {
fun onSee()
fun onHear() { /* default implementation */ }
fun onSmell(){ /* default implementation */ }
fun onTouch(){ /* default implementation */ }
fun onAwake(){ /* default implementation */ }
fun onSleep(){ /* default implementation */ }
}
Now when you create an instance of this interface you only need to provide a compulsory implementation for onSee() method, rest are optional
If you're not the author of the original interface
You could extend the original interface and provide a default implementation for the methods you want
interface OnSeeEventHandler: EventHandler {
override fun onHear() { /* default implementation */ }
override fun onSmell(){ /* default implementation */ }
override fun onTouch(){ /* default implementation */ }
override fun onAwake(){ /* default implementation */ }
override fun onSleep(){ /* default implementation */ }
}
And use the OnSeeEventHandler to provide only onSee method imeplementation
I came up with the following, somewhat p̶e̶r̶v̶e̶r̶s̶e̶ interesting approach.
The function below uses a dynamic proxy to "materialize" an interface and patch it with only the needed methods. Methods that are not patched will just return null or Unit, depending on the return type.
import java.lang.reflect.Proxy.newProxyInstance
inline fun <reified T> Any.materialize(): T = materialize(T::class.java, this)
fun <T> materialize(i: Class<T>, x: Any = object {}): T {
#Suppress("UNCHECKED_CAST")
return newProxyInstance(i.classLoader, arrayOf(i)) { _, m, args ->
x.javaClass.methods
.asSequence()
.filter {
it.name == m.name
&& it.parameterTypes!!.contentEquals(m.parameterTypes)
}
.map {
it.invoke(x, *args.orEmpty())
}.firstOrNull()
} as T
}
It can then be used as follow, given an interface Foo and an anonymous object that contains only an implementation of its qux() function:
interface Foo {
fun bar()
fun baz(): String
fun qux(s: String): String
}
fun main(vararg args: String) {
val foo = object {
fun qux(s: String): String {
return "Returned from qux: $s"
}
}.materialize<Foo>()
println(foo.bar()) // void no-op, prints "kotlin.Unit"
println(foo.baz()) // no-op with return value, prints "null"
println(foo.qux("Hello")) // prints "Returned from qux: Hello"
}
Disclaimer
Using this, you lose all compile-time checking as everything is resolved at runtime.
Some things are not covered by this implementation (e.g. interface default methods).
Performance is not taken into account at all.
Requires the kotlin-reflect dependency.
Today is my second day learning Kotlin, so there might be any number of unaddressed edge cases and bugs.
I would not use this myself in most
cases, and will continue to hold out for a Kotlin construct that supports partial
interface implementations (like TypeScript's Partial<T>).
I'm only providing
this approach because it might be of interest for some use cases, and I'm
sorry if this made your eyes bleed.

How kotlin delegation is useful?

I'm really confused about the kotlin delegation. Let me describe the regular polymorphism approach here which looks same like the kotlin delgation.
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
fun main(args: Array<String>) {
val b : Base = BaseImpl(10)
b.print() // prints 10
}
I can pass any implemented class of Base interface to b variable to call the method of specified class's object. Then what is the benefit of kotlin's delegation? Which is described here.
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b // why extra line of code?
// if the above example works fine without it.
fun main(args: Array<String>) {
val b = BaseImpl(10)
Derived(b).print() // prints 10
}
I know this is the simple scenario where the both codes are working fine. There should be a benefit of delegation that's why kotlin introduced it. What is the difference? and how kotlin delegation can be useful? Please give me a working example to compare with polymorphism approach.
Also remember that you're not restricted to just one delegate. Kotlin's way of implementing delegation is similar to traits implementation in languages like Groovy. You can compose different functionality via delegates. Kotlin's way can also be considered more powerful because you can "plug in" different implementations too.
interface Marks {
fun printMarks()
}
class StdMarks() : Marks {
override fun printMarks() { println("printed marks") }
}
class CsvMarks() : Marks {
override fun printMarks() { println("printed csv marks") }
}
interface Totals {
fun printTotals()
}
class StdTotals : Totals {
override fun printTotals() { println("calculated and printed totals") }
}
class CheatTotals : Totals {
override fun printTotals() { println("calculated and printed higher totals") }
}
class Student(val studentId: Int, marks: Marks, totals: Totals)
: Marks by marks, Totals by totals
fun main(args:Array<String>) {
val student = Student(1,StdMarks(), StdTotals())
student.printMarks()
student.printTotals()
val cheater = Student(1,CsvMarks(), CheatTotals())
cheater.printMarks()
cheater.printTotals()
}
Output:
printed marks
calculated and printed totals
printed csv marks
calculated and printed higher totals
You can't do this with inheritance.
It is extremely useful for creating decorators and for object composition.
Joshua Bloch in Effective Java, 2nd Edition, Item 16 'Favor Composition Over Inheritance' shows a good example: inheritance is easy-to-break, and decorators are not.
Inheritance:
class LoggingList<E> : ArrayList<E>() {
override fun add(e: E): Boolean {
println("added $e")
return super.add(e)
}
override fun addAll(e: Collection<E>): Boolean {
println("added all: $e")
return super.addAll(e) // oops! Calls [add] internally.
}
}
Delegation:
class LoggingList<E>(delegate: MutableList<E>) : MutableList<E> by delegate {
override fun add(e: E): Boolean {
println("added $e")
return delegate.add(e)
}
override fun addAll(e: Collection<E>): Boolean {
println("added all: $e")
return delegate.addAll(e) // all OK
// it calls [delegate]'s [add] internally, not ours
}
}
It is useful because of the Delegation Pattern where most of the behavior can be the same as the target of the delegation (b) but you just want to override a subset of methods to act differently.
An example would be an InputStream implementation which delegates all work to another InputStream but overrides the close() method to not close the underlying stream. This could be implemented as:
class CloseGuardInputStream(private val base: InputStream)
: InputStream by base {
override fun close() {}
}
Following is the example :-
interface Mode{
val color:String
fun display()
}
class DarkMode(override val color:String) : Mode{
override fun display(){
println("Dark Mode..."+color)
}
}
class LightMode(override val color:String) : Mode {
override fun display() {
println("Light Mode..."+color)
}
}
class MyCustomMode(val mode: Mode): Mode{
override val color:String = mode.color
override fun display() {
mode.display()
}
}
Now, the custom mode can reuse display() function of both modes DarkMode & LightMode
fun main() {
MyCustomMode(DarkMode("CUSTOM_DARK_GRAY")).display()
MyCustomMode(LightMode("CUSTOM_LIGHT_GRAY")).display()
}
/* output:
Dark Mode...CUSTOM_DARK_GRAY
Light Mode...CUSTOM_LIGHT_GRAY
*/
Kotlin natively support delegation pattern.
Kotlin provides by keyword to specify the delegate object which our custom mode will be delegating to.
We can achieve the same result of the code above using by keyword.
class MyCustomMode(val mode: Mode): Mode by mode
fun main() {
MyCustomMode(DarkMode("CUSTOM_DARK_GRAY")).display()
MyCustomMode(LightMode("CUSTOM_LIGHT_GRAY")).display()
}
/* output:
Dark Mode...CUSTOM_DARK_GRAY
Light Mode...CUSTOM_LIGHT_GRAY
*/