8

I am having the following error with this piece of code, which makes no sense to me:

fun spawnWorker(): Runnable {
    return Runnable {
        LOG.info("I am a potato!")
        return
    }
}

My IDE says this to me:

enter image description here

But the Runnable interface says otherwise:

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

What is the reason why I can't have a return there, but without any return it compiles fine:

fun spawnWorker(): Runnable {
    return Runnable {
        LOG.info("I am a potato!")
    }
}
PedroD
  • 5,670
  • 12
  • 46
  • 84

2 Answers2

15

A plain return returns from the nearest enclosing function or anonymous function. In your example, the return is non-local and returns from spawnWorker and not from the Runnable SAM adapter. For a local return, use the labeled version:

fun spawnWorker(): Runnable {
    return Runnable {
        LOG.info("I am a potato!")
        return@Runnable
    }
}
Ingo Kegel
  • 46,523
  • 10
  • 71
  • 102
  • Thanks! I wasn't aware that the kotlin compiler could not check the scope in which I am using that return, it is the first time I see these behaviour in a functional language. – PedroD Dec 20 '16 at 21:46
  • 3
    It's not that the compiler couldn't check the scope, indeed it checks the scope and prohibits non-local return from that scope. The return statement was deliberately designed to return from the closest non-lambda function to enable inline functions with lambdas, such as `forEach`, `synchronized`, etc, look like language constructs. More details about return statements here: https://kotlinlang.org/docs/reference/returns.html#return-at-labels – Ilya Dec 20 '16 at 23:23
2

You are using a lambda-to-SAM conversion, thus trying to return from a lambda statement, which is not allowed to have a return on its own.

Your code

fun spawnWorker(): Runnable {
    return Runnable { LOG.info("I am a potato!") }
}

Means the same as

fun spawnWorker(): Runnable {
    return { LOG.info("I am a potato!") }
}

Compare it to returning an object, which is the direct translation from Java:

fun spawnWorker(): Runnable {
    return object : Runnable {
        override fun run() {
            LOG.info("I am a potato!")
            return // don't really need that one
        }
    }
}
voddan
  • 31,956
  • 8
  • 77
  • 87