8

I have an existing Java class ThreadUtils with a method every that looks like:

public class ThreadUtil {

    public static Thread every(int seconds, Runnable r) {
        Thread t = new Thread(() -> {
            while(true) {
                r.run();
                try {
                    Thread.sleep(1000 * seconds);
                } catch (InterruptedException e) {
                    return;
                }
            }
        });
        t.start();
        return t;
    }
}

And I'm trying to convert it to Kotlin. I'm a bit hung up on the Runnable closure. This fails with a bad return:

fun every(seconds: Int, r: Runnable): Thread {
    val t = Thread({
        while (true) {
            r.run()
            try {
                Thread.sleep((1000 * seconds).toLong())
            } catch (e: InterruptedException) {
                return // ERROR: This function must return a value of type Thread
            }
        }
    })
    t.start()
    return t
}

I also tried pulling the Runnable out just to help myself separate things, but this also fails the same way:

fun every(seconds: Int, r: Runnable): Thread {
    val internalRunnable = Runnable {
        while (true) {
            r.run()
            try {
                Thread.sleep((1000 * seconds).toLong())
            } catch (e: InterruptedException) {
                return // ERROR: This function must return a value of type Thread
            }
        }
    }
    val t = Thread(internalRunnable)
    t.start()
    return t
}

How can I implement a @FunctionalInterface or similar-style closure/lambda that doesn't try to return from the function in which it's being defined?

Craig Otis
  • 31,257
  • 32
  • 136
  • 234
  • I work everyday with some so-called smart people inventions (aka projects), and this makes my work as a dev a nightmare, you mix uneccesserly technologies and ruin your, and others life doing so. Why you can't use java? Isn't it look stupid, to have to tell the language, that you are returning from a Thread writing that return statement inside a Thread? Do you feel what is good and what is bad? Do you have aesthetic sense when creating something? Progress is not when you just do another random thing, progres is when you feel it is right thing to do. Making more trouble isn't progress at all. – Krzysztof Cichocki Apr 12 '17 at 11:58

1 Answers1

11

In Kotlin, return statements inside lambdas work differently from those in Java. If you write just return, it means return from the innermost function declared with keyword fun, and it ignores lambdas -- in your code, it means 'return from every'.

To return from a lambda, use qualified return@label-- in your case, it's return@Thread (and return@Runnable for the second example), like in this simplified snippet:

for (i in 1..4) {
    Thread { 
        if (i % 2 == 0)
            return@Thread
        println("Thread $i")
    }.run()
}

(runnable demo of this code)

Also, there is a thread { ... } function in kotlin-stdlib that you might find useful (and, similarly, the return statement for its lambda is return@thread).

You can find a more detailed explanation in the language reference and in this answer.

Community
  • 1
  • 1
hotkey
  • 140,743
  • 39
  • 371
  • 326
  • Ah great, I didn't realize the difference in the `return` behavior - thanks for pointing that out, and for the `thread { }` shortcut. – Craig Otis Apr 12 '17 at 11:42
  • 3
    should be `.start()` instead of `.run()` to be started in a different thread. – hevi Aug 02 '19 at 13:53