Kotlin - Automatically match overriden function type? - kotlin

I'm trying to write a function that is essentially a wrapper method around some other functionality, for instance, some logging function.
I've tried several combinations of inline, generic, reified, etc., but nothing seems to work.
My function looks like this:
fun log(note: String, block: () -> Unit): () -> Unit {
print(note)
return block
}
My idea here is to perform some simple operation on the incoming note, and then just return that incoming function to be used as it was originally.
However, I want to do this around overridden functions like so:
override fun onClick(clicked: View) = log("Green Button") {
// here the regular onClick functionality goes
}
Here, I get an error "Return type is () -> Unit, which is not a subtype of overridden". This makes sense enough, as the function signatures do not match.
However, when I do this with other random functions:
fun test() = log("foo") { ... }
fun otherTest(a: String, b: Int) = log("bar") { ... }
I get no errors, and the interpreter somehow seems fine with this. I also tried looking at something like GlobalScope.launch to take that approach, but I couldn't figure it out.
Is what I'm trying to do possible? If not, is there something close?

I think
inline fun log(note: String, block: () -> Unit): Unit {
print(note)
return block()
}
should do what you want. It can be generalized to
inline fun <T> log(note: String, block: () -> T): T {
print(note)
return block()
}
I get no errors, and the interpreter somehow seems fine with this.
Why is that surprising? Those functions just return () -> Unit. If you do e.g.
fun test() = log("foo") { print("bar") }
then calling test() won't print bar; calling test()() will.

Tell me if my understanding is wrong. This is my approach
Extension function:
fun View.onClickWithLog(str: String, l: () -> Unit) {
setOnClickListener { Log.d("LogTag", str); run(l) }
}
Usage (from Activity):
btnTest.onClickWithLog("My Button String"){
Log.d("Actions from Activity", "Content")
finish()
}
and the output is
D/LogTag: My Button String
D/Actions from Activity: Content
which prints your note first, and execute the actions in the lambda expression.

When you use the = operator to assign something to a fun, the expression on the right hand side is supposed to return the return type of that fun
The original fun onClick(clicked:View) : Unit has return type Unit. When you write
override fun onClick(clicked:View) = ... , the ... is what you get when you call onClick(v) so it should be a Unit instead of a View -> Unit (Not even () -> Unit as in your code)
Take a simpler example. Let say you have fun sum(a:Int,b:Int) : Int. When you write override fun sum(a:Int,b:Int) = ... , ... must be an Int instead of a (Int,Int) -> Int since you expect to get an Int immediately when you call sum(a,b). If you somehow got a let say
val someOtherWayToSum : (Int,Int) -> Int = {...}
and want to use it, you can write
override fun sum(a:Int,b:Int) = someOtherWayToSum(a,b)
In your case, you better just do
override fun onClick(clicked:View){
/* some operation (e.g your log)*/
/* the regular onClick functionality */
}
since you are overriding it and implementing its regular functionality right there anyway.

Related

How to define a method only when class generic type satisfies a test?

I am trying to do something like the following:
class Event<TPayload>() {
fun subscribe(handler: (payload: TPayload) -> Unit) { ... }
fun subscribe(handler: () -> Unit) where TPayload : Unit { ... }
}
The intention is that instances of Event<Unit> will have two overloads of subscribe(), but other instances will only have one.
The above code will not compile. I tried using extension methods, but would have to use a different name for the extra method, rather than overloading it.
You can define that second function as an extension function so it only appears for Events who have a type of Unit. It's okay to overload the function name. Define it outside the class:
inline fun Event<Unit>.subscribe(crossinline handler: ()->Unit) =
subscribe { handler() }
Test:
class Event<T> {
private val subscribers = mutableListOf<(T)->Unit>()
fun subscribe(handler: (payload: T) -> Unit) {
subscribers += handler
}
fun send(payload: T) {
for (subscriber in subscribers) subscriber(payload)
}
}
fun main() {
val event = Event<Unit>()
// Using verbose syntax to prove it's the extension function being used
// and not a lambda with implicit 'it':
event.subscribe(fun() { println("got unit") })
event.send(Unit)
}
If you use a lambda, the compiler will use the first subscribe function with an implicit it parameter since it takes precedence in overload resolution. But runtime behavior would be the same either way if you aren't using the parameter.

Is it possible to null T or 'this' at the end of generic function for Kotlin?

I have in my project a listener. It is assigned to drawerLayout. I would like to in lambda function remove it and null it at once (sequentially). Is it possible to null T or this at the end of generic function.
Here is my code:
// Usage
actionBarListener?.let {
drawerLayout.removeDrawerListener(it) // remove listener
actionBarListener = null // null it
}
// Usage expected
actionBarListener.releaseAndSetNull {
drawerLayout.removeDrawerListener(it) // remove listener and null it
}
// Generic
fun <T> T?.releaseAndSetNull(block: (T?) -> Unit) = apply {
this?.apply { block.invoke(this) }
this = null // Error: variable expected
}
As Ivo Beckers said, this function would only work on vars, i.e. KMutableProperty0<T>. So you could write an extension on KMutableProperty0<T?>, and use reflection to set it, if you don't mind using reflection, that is.
inline fun <T: Any> KMutableProperty0<T?>.releaseAndSetNull(block: (T?) -> Unit) {
block(this.get())
this.set(null)
}
// or if you don't want the block to be called if the property is null:
inline fun <T: Any> KMutableProperty0<T?>.releaseAndSetNull(block: (T) -> Unit) {
this.get()?.run(block)
this.set(null)
}
Then suppose you have a property:
var foo: Int? = 10
You can do:
::foo.releaseAndSetNull { println("Foo: $it") }
// or if foo belongs to someObject
someObject::foo.releaseAndSetNull { println("Foo: $it") }
Looking at the generated bytecode, the way this is implemented (which is subject to change) is that each unique property referred to by a property reference in this way causes an inner class to be generated. The inner class will then have get and set methods that do their jobs with little extra cost - as they can just set the right property directly. So really the main cost is the extra inner class that is generated.
I can think of several reasons why this could never work.
First of, the generic function doesn't know if this is a var or val. And this functionality could only works on a var
Likewise, it can't know if it's nullable, that's also a requirment.
Furthermore, it can even be the case that it's not a variable that's calling the function.
Like say you have
fun getActionBarListener() {
return actionBarListener
}
Then somewhere else you could do
getActionBarListener().releaseAndSetNull {
drawerLayout.removeDrawerListener(it) // remove listener and null it
}
How do you expect that to work?
Or even anonymous objects could call this function.

How to Resolve Function Template Generics for Signal/Slot System?

I'm trying to develop a simplistic signals/slots system in Kotlin. Here's what I have so far:
open class Signal<T : Function<Unit>>() {
val callbacks = mutableListOf<T>()
open fun addCallback(slot: T) {
callbacks.add(slot)
}
open fun emit(vararg params: Any) {
for(call in callbacks) {
call(*params)
}
}
}
fun test(myarg: Int) = println(myarg)
fun main(args: Array<String>) {
val myevent = Signal<(Int) -> Unit>()
myevent.addCallback(::test)
myevent.emit(2)
}
The idea is one would create an instance of Signal along with a generic template to dictate which parameters are used for the callbacks. Callbacks can then be added to the Signal. Finally, whenever the Signal needs to be... well... "signaled", the emit method is used. This method passes all the parameters to the corresponding callbacks if necessary.
The issue is this code results in the following error:
kotlin\Signal.kt:30:4: error: expression 'call' of type 'T' cannot be invoked as a function. The function 'invoke()' is not found
The line in question is:
call(*params)
Any recommendations on how to handle things from here?
This is because Function is an empty interface (source).
The various function types that actually have invoke operators are all defined one by one here, as Function0, Function1, etc.
I don't think you'll be able to create a Signal implementation that may have callbacks with any number and any type of parameters. Could you perhaps get by with only having callbacks with a single parameter?
open class Signal<T> {
val callbacks = mutableListOf<(T) -> Unit>()
open fun addCallback(slot: (T) -> Unit) {
callbacks.add(slot)
}
open fun emit(param: T) {
for (call in callbacks) {
call(param)
}
}
}
fun test(myarg: Int) = println(myarg)
fun main(args: Array<String>) {
val myevent = Signal<Int>()
myevent.addCallback(::test)
myevent.emit(2)
}
(Note that you could replace both usages of (T) -> Unit here with Function1<T, Unit>.)

how to implement an applyif for Kotlin?

I'd like to have an applyif to work like:
builder.applyif(<condition expression>) {
builder.set...
}
to be equal with:
builder.apply {
if (<condition expression>) {
builder.set...
}
}
Is that possible?
Yes, of course. You can nearly program anything, but don't reinvent the wheel. Look at the bottom of the answer to see a standard Kotlin approach without own extension function(s) which may already suffice your needs (not exactly applyIf though).
Now, however, lets see how an applyIf might be implemented:
inline fun <T> T.applyIf(predicate: T.() -> Boolean, block: T.() -> Unit): T = apply {
if (predicate(this))
block(this)
}
Don't forget the inline if you are implementing extension functions with lambdas.
Here is an example usage of the above.
// sample class
class ADemo {
fun isTrue() = true
}
// sample usage using method references
ADemo().applyIf(ADemo::isTrue, ::println)
// or if you prefer or require it, here without
ADemo().applyIf( { isTrue() } ) {
println(this)
}
If you just want to supply a boolean instead, you can use the following extension function:
inline fun <T> T.applyIf(condition : Boolean, block : T.() -> Unit) : T = apply {
if(condition) block(this)
}
and call it with:
val someCondition = true
ADemo().applyIf(someCondition) {
println(this)
}
And now a possible Kotlin standard way with which more people could be familiar:
ADemo().takeIf(ADemo::isTrue)
?.apply(::println)
// or
ADemo().takeIf { it.isTrue() }
?.apply { println(this) }
If they do remember (I actually didn't until I saw Marko Topolniks comment) they should immediately know what's going on.
However, if you require the given value (i.e. ADemo()) after calling takeIf this approach might not work for you as the following will set the variable to null then:
val x = ADemo().takeIf { false }
?.apply { println(this) /* never called */ }
// now x = null
whereas the following will rather set the variable to the ADemo-instance:
val x = ADemo().applyIf(false) { println(this) /* also not called */ }
// now x contains the ADemo()-instance
Chaining the builder calls might not be so nice then. Still you can also accomplish this via standard Kotlin functions by combining the takeIf with apply or also (or with, let, run, depending on whether you want to return something or not or you prefer working with it or this):
val x = builder.apply {
takeIf { false }
?.apply(::println) // not called
takeIf { true }
?.apply(::println) // called
}
// x contains the builder
But then again we are nearly there where you were already in your question. The same definitely looks better with applyIf-usage:
val x = builder.applyIf(false, ::println) // not called
.applyIf(true) {
println(this) // called
}
// x contains the builder
Sure you can, you just need an extension function so you can call it on the builder, and you need it to take a Boolean parameter and the lambda to execute.
If you look at the source of the apply function itself, it will help with most of the implementation:
public inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}
Based on this, applyIf can be as simple as:
inline fun <T> T.applyIf(condition: Boolean, block: T.() -> Unit): T {
return if (condition) this.apply(block) else this
}
Usage looks like this:
builder.applyIf(x > 200) {
setSomething()
}
fun <T> T.applyIf(condition: Boolean, block: T.() -> T) = if (condition) block() else this
fun main() {
println("a".applyIf(true) { uppercase() }) // A
println("a".applyIf(false) { uppercase() }) // a
}

Is there a built in Kotlin method to apply void function to value?

I wrote this method to apply a void function to a value and return the value.
public inline fun <T> T.apply(f: (T) -> Unit): T {
f(this)
return this
}
This is useful in reducing something like this:
return values.map {
var other = it.toOther()
doStuff(other)
return other
}
To something like this:
return values.map { it.toOther().apply({ doStuff(it) }) }
Is there a language feature or method like this already build in to Kotlin?
Apply is in the Kotlin standard library: See the docs here: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html
Its method signature:
inline fun <T> T.apply(f: T.() -> Unit): T (source)
Calls the specified function f with this value as its receiver and returns this value.
I ran into the same problem. My solution is basicly the same as yours with a small refinement:
inline fun <T> T.apply(f: T.() -> Any): T {
this.f()
return this
}
Note, that f is an extension function. This way you can invoke methods on your object using the implicit this reference. Here's an example taken from a libGDX project of mine:
val sprite : Sprite = atlas.createSprite("foo") apply {
setSize(SIZE, SIZE)
setOrigin(SIZE / 2, SIZE / 2)
}
Of course you could also call doStuff(this).