I want to print a() message using lambda, but I can't do this.
printed Nothing in console. How can I do it?
var quackBehavior: QuackBehavior? = null
fun a(){
quackBehavior?.let{
it("I want print this message")
}
}
fun printMessage(){
quackBehavior = {
println(it)
}
}
fun main() {
a()
}
typealias QuackBehavior = (String) -> Unit
``
In your code you don't call printMessage function, so quackBehavior remains null. If you add printMessage() call in main function before a() call, it will work as intended.
quackBehavior?.let {
it("I want print this message")
}
The lambda you passed to let will only be invoked if quackBehaviour != null. This is the case because you use the safe call operator ?. which will only invoke functions on a non-null receiver.
Since you don't call printMessage, where you intialize quackBehaviour it remains null.
So to fix it, invoke your functions like this:
fun main() {
printMessage()
a()
}
Optional:
You could simplify your code like this:
fun main() {
var quackBehavior: (String) -> Unit = {
println(it)
}
quackBehavior("I want print this message")
}
Related
I have the following function.
suspend fun result() = suspendCancellableCoroutine<Int> {continuation ->
val callback = object : Callback {
continuation.resume(value)
}
}
and then I call result in a Coroutine as follows:
someCoroutine {
when (result()){
x -> doSomething
y -> doSomething
...
}
}
It works, but I keep getting the error when its called again:
Uncaught exception: Already resumed, but proposed with update.
I figured I need a callbackFlow instead, but I'm not too sure as to how to implement it. Here's what I have so far.
suspend fun result() = callbackFlow<Int> {
val callback = object : Callback {
trySendBlocking(value)
}
awaitClose()
}
I'm guessing I have to use collect(), but I don't know how to process it in the coroutine. Any help would be appreciated.
To use values emitted by Flow you need to use one of the terminal operators, for example collect:
coroutineScope.launch {
result().collect { value ->
when (value) {
x -> doSomething
y -> doSomething
...
}
}
}
I'm quite new to Kotlin and I'd like to see if using high-order functions can help in my case.
My use-case is that I need to call the methods of an IInterface derived class to send events to one or more components. And I'd like to make this generic, and I want to check if a high-order funtion can help. A sample of code will help to understand (well, I hope so!).
private val eventListeners = mutableListOf<IEventInterface>() // List filled somewhere else!
private fun sendConnectionEvent(dummyString: String) {
val deadListeners = mutableListOf<IEventInterface>()
eventListeners.forEach {
try {
it.onConnectionEvent(dummyString)
} catch (e: DeadObjectException) {
Log.d(TAG, "Removing listener - Exception ${e.message}")
deadListeners.add(it)
}
}
deadListeners.forEach { it ->
eventListeners.remove(it)
}
}
private fun sendWonderfulEvent(dummyString: String, dummyInt: Int) {
val deadListeners = mutableListOf<IEventInterface>()
eventListeners.forEach {
try {
it.onWonderfulEvent(dummyString, dummyInt)
} catch (e: DeadObjectException) {
Log.d(TAG, "Removing listener - Exception ${e.message}")
deadListeners.add(it)
}
}
deadListeners.forEach { it ->
eventListeners.remove(it)
}
}
I added 2 similar methods (I will have many more in the real use case) and I think (I hope!) that something could be done but I can't make high-order function works in this case because:
I want to call the same method on several instances, and not 'just' a basic function
To make things even worse, the methods I need to call don't have the same prototype (that would have been too easy!).
Hope this is clear enough.
Thanks for your help!
VR
Here is how it can be done
fun onEvent(body: (IEventInterface) -> Unit) {
val deadListeners = mutableListOf<IEventInterface>()
eventListeners.forEach {
try {
body(it)
} catch (ex: DeadObjectException) {
Log.d(TAG, "Removing listener - Exception ${e.message}")
deadListeners.add(it)
}
}
deadListeners.forEach { it ->
eventListeners.remove(it)
}
}
Supposing an interface like this:
interface IEventInterface {
fun onConnectionEvent(dummyString: String)
fun onWonderfulEvent(dummyString: String, dummyInt: Int)
}
Define an generic type that implements your defined interface ( <T : IEventInterface>)
Define an mutable list of this type to receive your implementation (MutableList<T>.removeIfThrows)
Expect an extension function for you type that will do your specific validation (and custom parameters if you want)
Using an apply and returning the instance you can run your code like a pipeline
Executing the custom validation when you want
private fun <T : IEventInterface> MutableList<T>.removeIfThrows(validation: T.() -> Unit, customLogMessage: String? = null): MutableList<T> {
return apply {
removeIf {
it.runCatching {
validation()
}.onFailure { error ->
print(customLogMessage ?: "Removing listener - Exception ${error.message}")
}.isFailure
}
}
}
Define your specific implementation passing just the function with custom validation as an parameter
private fun <T : IEventInterface> MutableList<T>.sendConnectionEvent(dummyString: String) = removeIfThrows({
onConnectionEvent(dummyString)
})
private fun <T : IEventInterface> MutableList<T>.sendWonderfulEvent(dummyString: String, dummyInt: Int) = removeIfThrows({
onWonderfulEvent(dummyString, dummyInt)
})
Now you can run your code like an pipeline modifying your original object like this
private fun nowYouCanDoSomethingLikeThis() {
eventListeners
.sendConnectionEvent("some dummy string")
.sendWonderfulEvent("some another dummy string", 123)
}
I have a function that catches recoverable exceptions and returns a fallback
private fun <T> safely(block: () -> T, fallback: T): T {
return try {
block()
} catch(exc: SomeException) {
// Log the exception/do some logic
fallback
}
}
I want to be able to add this to the public methods of my class e.g.
fun doSomething(): List<String> = safely({
val list = mutableListOf<String>("Hello")
fun someCheck1() = false // Some boolean value
fun someCheck2() = true // Some boolean value
do {
if(someCheck2()) {
return arrayListOf<String>("Hello", "World")
}
} while (someCheck1())
return list
}, arrayListOf<String>())
However I get compiler errors 'return' is not allowed here
Yet if I remove the return then my return in the loop no longer works and it gets highlighted in my IDE with warning the expression is never used
How can I maintain this type of return logic within a Lambda?
Playground Example
Try
fun doSomething(): List<String> = safely(
{
val list = mutableListOf<String>("Hello")
fun someCheck1() = false // Some boolean value
fun someCheck2() = true // Some boolean value
do {
if (someCheck2()) {
return#safely arrayListOf<String>("Hello", "World")
}
} while (someCheck1())
list
}
, arrayListOf<String>())
For further reference, check Using return inside a lambda?
Or you can also extract your block into a separate function (i.e. someCheckFunction(): List<String>), and have fun doSomething() = safely({ someCheckFunction() }, arrayListOf()), but I guess you want to maintain lambda code like above.
return arrayListOf<String>("Hello", "World") here tries to return a value from doSomething function rather than from the lambda passed to safely. However, such return is non-local, since it tries to exit from the function that is not on the top of stack, and therefore it is prohibited.
Another option here is to make safely function inline:
inline fun <T> safely(block: () -> T, fallback: T): T { ... }
and then you'll be able to make a non-local return from block lambda function passed to it.
With all the well-known single-function listeners we can use a simpler lambda notation
view.setOnClickListener { do() }
instead of the original, longer Java way of
view.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
do()
}
})
But what exactly makes this work? I tried to do the same with my own listener:
private var listener: OnCopyPasteClickListener? = null
interface OnCopyPasteClickListener {
fun onPasteClick(text: String)
}
fun setOnCopyPasteClickListener(onCopyPasteClickListener: OnCopyPasteClickListener) {
listener = onCopyPasteClickListener
}
and while the long approach works just fine:
copypaste.setOnCopyPasteClickListener(object : CopyPasteMenu.OnCopyPasteClickListener {
override fun onPasteClick(text: String) {
do(text)
}
})
I can't make it accept the short one:
copypaste.setOnCopyPasteClickListener {
do(it)
}
The IDE gives a type mismatch error.
Actually, if you have only one function to be invoked, I recommend you use Kotlin Callback.
typealias OnDoWorkListener = ((String) -> Unit)
class Work {
var doWork: OnDoWorkListener? = null
fun doSomething() {
doWork?.invoke("Message Here")
}
}
And in your function, you just set the callback to it
fun main() {
val work = Work()
work.doWork = {
Log.d("WORK", "This gets called from the `work` object. Message: $it")
}
work.doSomething();
}
We can also use function to set the listener as well.
class Work {
var doWork: OnDoWorkListener? = null
fun doSomething() {
doWork?.invoke("Message Here")
}
fun setOnWorkListener(listener: OnDoWorkListener) {
doWork = listener
}
}
fun main() {
val work = Work()
work.setOnWorkListener {
Log.d("WORK", "This gets called from the `work` object. Message: $it")
}
work.doSomething()
}
Higher order functions make this work:
Kotlin functions are first-class, which means that they can be stored
in variables and data structures, passed as arguments to and returned
from other higher-order functions. You can operate with functions in
any way that is possible for other non-function values.
From the same page:
Passing a lambda to the last parameter
In Kotlin, there is a convention that if the last parameter of a
function accepts a function, a lambda expression that is passed as the
corresponding argument can be placed outside the parentheses:
val product = items.fold(1) { acc, e -> acc * e }
If the lambda is the only argument to that call, the parentheses can
be omitted entirely:
run { println("...") }
Knowing this, a possible update on your class would look like:
class CopyPaste {
private var listener: (String) -> Unit = {}
fun setOnCopyPasteClickListener(onCopyPasteClickListener: (String) -> Unit) {
listener = onCopyPasteClickListener
}
fun doCopyPaste(value: String) {
listener.invoke(value)
}
}
fun main() {
val copyPaste = CopyPaste()
copyPaste.setOnCopyPasteClickListener { println(it) }
copyPaste.doCopyPaste("ClipboardContent!")
}
The class CopyPaste stores the listener, which is a function that takes a String parameter and does not return anything. Its function setOnCopyPasteClickListener accepts a function with the same signature as the listener property and at the end doCopyPaste accepts a String parameter and passes it to the stored function.
Actually, just after I posted, I searched for more thoughts and found this thread: https://youtrack.jetbrains.com/issue/KT-7770 This is indeed a debated limitation as it currently only applies to Java, not Kotlin itself. There is also a suggestion there that gives almost the required simplicity:
interface OnCopyPasteClickListener {
fun onPasteClick(text: String)
companion object {
inline operator fun invoke(crossinline op: (text: String) -> Unit) =
object : OnCopyPasteClickListener {
override fun onPasteClick(text: String) = op(text)
}
}
}
and then, thanks to this overloaded operator, it can be called as:
copypaste.setOnCopyPasteClickListener(CopyPasteMenu.OnCopyPasteClickListener { text ->
do(text)
})
But as the suggested answers offer a more idiomatic solution, I'll accept one of those, I only wanted to include this approach here for reference.
I'm trying to get familiar with the more advanced kotlin features, but i don't know why my little code example compiles and prints "Test A" while not printing "Test B".
Can anybody tell me why Test B is not printed?
class One{
fun delegate(operation: One.()-> Unit){
operation()
}
fun main(args: Array<String>){
val one= One()
fun One.doIt(){
println("Test A")
}
one.delegate { doIt() } //prints Test A
one.delegate {
fun One.doItDifferently(){
println("Test B") //not printed
}
}
}
That's because you don't call the function .toItDifferently(), you only define it (it is a local function, i.e. a function defined inside another function). Modify your example to call the function:
one.delegate {
fun One.doItDifferently(){
println("Test B")
}
doItDifferently() // <- here
}
(UPD, based on the comment) You can call delegate with an anonymous function like this:
one.delegate( // note the parenthesis, not the curly braces
fun One.(){
println("Test B")
}
)
This declaration
one.delegate {
fun One.doItDifferently(){
println("Test B") //not printed
}
}
will just create an empty function with a nested function. doItDifferently() is just declared, but never invoked. Hence, println("Test B") will never be executed.
You're not calling the function.
That is a local extension function on the class One and you are just declaring it. It now exists and is usable in the current scope, but does nothing by itself.
You would need to call/invoke it for it to do anything, as with any normal method:
one.delegate {
fun One.doItDifferently(){
println("Test B")
}
doItDifferently()
}
IntelliJ will actually give you a warning that this function is never used.
Edit: as per your comment, you aren't passing the function at all. This is not possible yet if you want to return the function as reflection does not support local functions.
If you try this:
class One {
fun delegate(operation: One.() -> KFunction<*>) {
operation().call(this)
}
}
fun main(args: Array) {
val one = One()
fun One.doIt() {
println("Test A")
}
one.delegate {
fun One.doItDifferently() {
println("Test B") //not printed
}
this::doItDifferently
}
}
You'll get:
Exception in thread "main" kotlin.reflect.jvm.internal.KotlinReflectionInternalError: Introspecting local functions, lambdas and anonymous functions is not yet fully supported in Kotlin reflection