Heyo, not sure if this is the right place or not, but I'm really curious about the idea of interface...
o
Heyo, not sure if this is the right place or not, but I'm really curious about the idea of interfaces that require implementers inherit from a specific class? Essentially this (and, bear with me, this isn't a great example :P)
Copy code
abstract class Thing {

    fun someFunctionWeWant(): String {
        // ...
        return "hello!"
    }

}

interface IThingAdjacentInterface : Thing {
    
    val someProp: String

    fun doSomething() {
        
        val data = someFunctionWeWant()
        
        // ...
        
    }

}

class Something : Thing(), IThingAdjacentInterface {

    override val someProp = "hi!"

}

fun processSomeStuff() {
    
    val items: List<IThingAdjacentInterface> = listOf(Something())

    // ...
    
    items.forEach { 
        it.doSomething()
        someMoreStuff(it.someProp)
    }
    
}
Funnily enough Intellij actually thinks this is absolutely okay, except that it highlights interfaces can't inherit from classes. Otherwise it's happy with this and completes methods. I'm currently feigning this with context receivers:
Copy code
interface IThingAdjacentInterface {
    
    val someProp: String

    context(Thing)
    fun doSomething() {
        
        val data = someFunctionWeWant()
        
        // ...
        
    }

}

// ...

fun processSomeStuff() {

    val items: List<Thing> = listOf(Something())

    // ...

    items
        .forEach {
            if (it is IThingAdjacentInterface) {
                // `run` means its context receiver is... itself, compiler is happy with this.
                it.run { doSomething() }
            }
        }

}
I got my hopes up for a moment when I noticed Intellij doesn't actually mind if you do this:
Copy code
context(Thing)
interface IThingAdjacentInterface
...but I think that's a bug since it doesn't actually cause anything nor prevent you applying the interface to other classes, nor provide its context properties from
Thing
. I had a look into Kotlin's history and other questions about this and found that apparently Traits used to have this functionality via allowing them to inherit from classes, but I think that's a bit different to this. The final piece of the puzzle here I'd point to as well is that I, in the code I'm working with, do not have the option to simply define an interface for the functionality of
Thing
. That'd resolve the whole issue, but
Thing
already exists and I cannot modify its definition to add an interface implementation there.
s
How about delegation?
Copy code
interface Thing {
  fun someFunctionWeWant(): String
}

class ConcreteThing : Thing {
  override fun someFunctionWeWant(): String = "hello!"
}

interface IThingAdjacentInterface : Thing {
  val someProp: String

  fun doSomething() {
    val data = someFunctionWeWant()
    // ...
  }
}

class Something : IThingAdjacentInterface, Thing by ConcreteThing() {
  override val someProp = "hi!"
}
Oh.... you said you can't make an interface 🤦 my bad
And you can't just make
IThingAdjacentInterface
an abstract class instead of an interface? That would make the code you shared work as-is, but I assume the real-world case is more tricky.
y
This is kinda dumb, but you could do:
Copy code
interface IThingAdjacentInterface {
  val asThing: Thing
  ...
  fun doSomething() {
    val data = asThing.someFunctionWeWant()
  }
}