Interface with generic type of the class implementing the interface? - kotlin

Having a class that implement a interface with generic type of "This" class
Is there a way to do this without a cast?
Simple code:
interface Triggerable<This: Triggerable<This>> {
var trigger: (This) -> Unit
fun triggerNow() = trigger(this as This)
}
class Test : Triggerable<Test>{
override var trigger: (Test) -> Unit = { /*...*/ }
}
The same a little more complex:
interface TriggerInterface<T> {
val trigger: (T) -> Unit
fun triggerNow()
}
interface Triggerable<T: Triggerable<T>>: TriggerInterface<T> {
override fun triggerNow() = trigger(this as T)
}
interface Signalable<T>: TriggerInterface<T> {
var value: T
override fun triggerNow() = trigger(value)
}
class Test : Triggerable<Test>{
override val trigger: (Test) -> Unit = { /*...*/ }
}

Should be possible like this
interface TriggerInterface<T: TriggerInterface<T>> {
val trigger: (T) -> Unit
fun triggerNow()
fun getThis(): T
}
interface Triggerable<T: TriggerInterface<T>>: TriggerInterface<T> {
override fun triggerNow() = trigger(getThis())
}
class Test : Triggerable<Test>{
override fun getThis(): Test = this
override val trigger: (Test) -> Unit = { /*...*/ }
}
Check http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206
I would also personally recommend to reconsider if you really need both TriggerInterface AND Triggerable (where one inherits from the other).

Calling override fun triggerNow() = trigger(this as T) you are trying to cast Triggerable<T> to T thats why compiler warns you about unchecked cast
having
val trigger: (TriggerInterface<T>) -> Unit
will allow you to call trigger with no casting
override fun triggerNow() = trigger(this)
to actually execute
override val trigger: (Test) -> Unit = { /*...*/ }
you need an instance of Test to pass inside of trigger which is not declared anywhere in your code yet

Related

Is it possible to verify at compile time whether the required function is called for the Factory Class in Kotlin?

class ModelFactory {
fun setA() : ModelFactory {
// blabla...
}
fun setB() : ModelFactory {
// blabla...
}
fun setC() : ModelFactory {
// blabla...
}
fun build() : Model {
// An error occurs if any of setA, setB, and setC is not called.
}
}
//example
fun successTest() {
ModelFactory().setA().setB().setC().build() // No error occurs at compile time
}
fun failTest() {
ModelFactory().setA().build() // An error occurs at compile time because setB and setC are not called.
}
It's awkward grammatically, but I think it's been expressed what I want.
I have already implemented an error-raising runtime for this requirement, but I want to check this at compile time.
If possible, I think I should use annotations. But is this really possible at compile time?
With Kotlin, I have been avoiding builder pattern, as we can always specify default values for non-mandatory fields.
If you still want to use a builder pattern, you can use Step builder pattern that expects all mandatory fields to be set before creating the object. Note that each setter method returns the reference of next setter interface. You can have multiple Step builders based on the combination of mandatory fields.
class Model(val a: String = "", val b: String = "", val c: String = "")
class StepBuilder {
companion object {
fun builder(): AStep = Steps()
}
interface AStep {
fun setA(a: String): BStep
}
interface BStep {
fun setB(b: String): CStep
}
interface CStep {
fun setC(c: String): BuildStep
}
interface BuildStep {
//fun setOptionalField(x: String): BuildStep
fun build(): Model
}
class Steps : AStep, BStep, CStep, BuildStep {
private lateinit var a: String
private lateinit var b: String
private lateinit var c: String
override fun setA(a: String): BStep {
this.a = a
return this
}
override fun setB(b: String): CStep {
this.b = b
return this
}
override fun setC(c: String): BuildStep {
this.c = c
return this
}
override fun build() = Model(a, b , c)
}
}
fun main() {
// cannot build until you call all three setters
val model = StepBuilder.builder().setA("A").setB("B").setC("C").build()
}

How to pass generically scoped suspend lambda to class method in Kotlin?

Want to have a function inside an open class which can accept a suspend lambda and run it.
I know this works when you specify the type explicitly but if possible need it to accept generically scoped lambdas.
class ChildClass : SuperClass() {
// does work :)
fun launch(block: suspend ChildClass.() -> Unit) =
coroutineThing { this.block() }
}
open class SuperClass {
// doesn't work :(
fun <T : SuperClass> launch(block: suspend T.() -> Unit) =
coroutineThing { this.block() }
}
The error I am getting is Expression 'block' of type 'suspend T.() -> Unit' cannot be invoked as a function. The function 'invoke()' is not found.
Edit:
Looking to eventually call this method from an instance of the ChildClass like this: ChildClass().launch { doStuff() }
You can write like this but I don't know how it works :) For me, it looks like Kotlin issue.
open class SuperClass {
fun <T : SuperClass> launch(block: suspend T.() -> Unit) =
coroutineThing { block.invoke(this as T) }
}
but in that case you have to invoke it like this:
ChildClass().launch<ChildClass> { println("test") }
but you can change it a bit to invoke it like you want:
open class SuperClass<T : SuperClass<T>> {
fun launch(block: suspend T.() -> Unit) =
coroutineThing { block.invoke(this as T) }
}
class ChildClass : SuperClass<ChildClass>()
//invokation
ChildClass().launch { println("test") }
How about this ?
open class SuperClass {
fun<T: SuperClass> launch(superClass: T, block: suspend T.() -> Unit) {
GlobalScope.launch {
superClass.block()
}
}
}
open class ChildClass: SuperClass() {
suspend fun print() {
}
}
fun test () {
val a = ChildClass()
a.apply {
launch(this) {
print()
}
}
}

Using lambdas does not compile when trying to pass in a method expecting a SAM interface

I am trying to understand lambdas and Kotlin. I created this trivial example
interface OnClickListener {
fun onClick(s: String)
}
class Button {
var clickListener: OnClickListener? = null
fun setOnClickListener(listener: OnClickListener?) {
clickListener = listener
}
fun click() {
clickListener?.onClick("hello")
}
}
fun main(args: Array<String>) {
val b = Button()
b.setOnClickListener(
object : OnClickListener {
override fun onClick(s: String) {
println(s)
}
}
)
/*
Variation 1
val l = {
s -> println(s)
}
b.clickListener = l*/
/*
Variation 2
b.setOnClickListener{
s -> println(s)
}
*/
/*
Variation 3
b.clickListener = {
s -> println(s)
}
*/
b.click()
}
So the above code only compiles if I pass an anonymous object. But I wanted to figure out how to use the lambdas.
None of the 3 variation to use a lambda compiles.
I thought since the OnClickListener is a SAM I should easily be able to pass in a lambda
What am I doing wrong here?
To be able to use a lambda, you need to use a Java interface.
First, create a Java file and create an interface:
public interface OnClickListener {
void onClick(String s);
}
Then in your main:
b.setOnClickListener(OnClickListener { s ->
println(s)
})
As for your Button class:
class Button {
var clickListener: OnClickListener? = null //You can use this too but there's another way as well.
//lateinit var clickListener: OnClickListener //Telling the compiler that you will initialize it later on.
fun setOnClickListener(listener: OnClickListener) { //removed redundant ? from the function signature.
clickListener = listener
}
fun click() {
clickListener?.onClick("hello") //Incase of lateinit, you don't need a '?' anymore
}
}
SAM conversion only works between a Java code and a Kotlin code.
EDIT: Since in Kotlin, you can store a function in a variable as well, here is my another two cents on how you can do it in a different way:
class Button {
lateinit var myFunction: (String) -> Unit
fun setOnClickListener(block : (String) -> Unit) {
myFunction = block //storing state of your 'listener'
}
fun onClick() = myFunction.invoke("Invoked from onClick function")
}
Then in your main:
fun main() {
val button = Button()
button.setOnClickListener { s ->
println(s)
}
button.onClick()
}
As Taseer Ahmad points out, SAM conversion only works for Java interfaces since Kotlin already has proper function types. Of course, an easy way around this is to simply define a second setOnClickListener method that takes a function type
class Button {
var clickListener: OnClickListener? = null
fun setOnClickListener(listener: OnClickListener?) {
clickListener = listener
}
inline fun setOnClickListener(crossinline listener: (String) -> Unit) {
setOnClickListener(object : OnClickListener {
override fun onClick(s: String) = listener(s)
})
}
fun click() {
clickListener?.onClick("hello")
}
}
This then allows you to write b.setOnClickListener { println(it) }. I always inline methods like this as a habit, but it's not really required, so you can remove the inline and crossinline if you want.

Scope Resolution Operator in Kotlin

I have read the following syntax. I have no idea why scope resolution operator is used in it.
class XyzFragment : Fragment() {
lateinit var adapter: ChatAdapter
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
if (!::adapter.isInitialized) { <-- This one
adapter = ChatAdapter(this, arrayListOf())
}
}
}
I want to know what is :: in if (!::adapter.isInitialized) { statement.
:: is a short form for this:: in Kotlin.
:: is a operator to creates a member reference or a class reference. For example,
class Test {
fun foo() {
}
fun foo2(value: Int) {
}
fun bar() {
val fooFunction = ::foo
fooFunction.invoke() // equals to this.foo()
val foo2Function = ::foo2
foo2Function.invoke(1) // equals to this.foo2(1)
val fooFunction2 = Test::foo
val testObject = Test()
fooFunction2.invoke(this) // equals to this.foo()
fooFunction2.invoke(testObject) // equals to testObject.foo()
}
}
This is mainly used in reflection and passing function.

Invoking methods on interfaces with generics

The following is a very simple illustration of what I'm trying to do:
interface Event {
fun value(): Int
}
class Event1: Event {
override fun value() = 1
}
class Event2: Event {
override fun value() = 2
}
interface EventConsumer<T> where T: Event {
fun consume(event: T)
}
class Event1Consumer: EventConsumer<Event1> {
override fun consume(event: Event1) {
println(event.value())
}
}
class Event2Consumer: EventConsumer<Event2> {
override fun consume(event: Event2) {
println(event.value())
}
}
class EventManager {
private val consumers: Map<KClass<*>, EventConsumer<*>> = mapOf(
Event1::class to Event1Consumer(),
Event2::class to Event2Consumer()
)
fun consume(event: Event) {
val consumer = consumers[event::class]
consumer?.consume(event)
}
}
The final method call (consumer.consume()) is giving me a compiler error
Out-projected type 'EventConsumer<*>?' prohibits the use of 'public
abstract fun consume(event: T): Unit defined in EventConsumer'
I know that Kotlin is a lot more strict about generics than Java which is probably why it doesn't work, but how would I implement something like this properly?
Since you are building the consumers map, it would be safe to make an unchecked cast to the correct generic EventConsumer type:
fun <T: Event> consume(event: T) {
val consumer = consumers[event::class] as? EventConsumer<T>
consumer?.consume(event)
}