When implementing an interface in Kotlin with an inline
function:
interface Foo { fun qux(fn: () -> Unit) } open class Bar : Foo { final override inline fun qux(fn: () -> Unit){TODO()} }
the IDE (and possibly the compiler) complains with this message:
Override by an inline function
To suppress this message, I have to use the @Suppress("OVERRIDE_BY_INLINE")
annotation. What is wrong?
What I am already aware:
However, this isn't the case when invoking a final function. In the example above, when I invoke bar.qux()
, the compiler can ensure that only this particular implementation will be used, and can safely inlined. It is irrelevant with whether it overrides the Foo.qux
method -- calling foo.qux
will use the non-inline version mentioned in point 1, and calling bar.qux
can inline safely.
Is this warning there only to make sure developers are aware of this? Or are there side effects?
"reified" is a special type of keyword that helps Kotlin developers to access the information related to a class at runtime. "reified" can only be used with inline functions. When "reified" keyword is used, the compiler copies the function's bytecode to every section of the code where the function has been called.
An Inline function is a kind of function that is declared with the keyword "inline" just before the function declaration. Once a function is declared inline, the compiler does not allocate any memory for this function, instead the compiler copies the piece of code virtually at the calling place at runtime.
Non-local returns In Kotlin, you can only use a normal, unqualified return to exit a named function or an anonymous function. To exit a lambda, use a label. A bare return is forbidden inside a lambda because a lambda cannot make the enclosing function return : fun ordinaryFunction(block: () -> Unit) { println("hi!")
Inline return converts a variable assignment to a return statement. Such a conversion is possible when the following statement after the assignment in the control flow returns the variable. This refactoring simplifies the control flow and makes it easier to reason about a function.
I know this is pretty late, but here's why. You got this right:
It is impossible to inline a virtual method.
But you should consider that, while Bar.foo
is not virtual in the sense that it could be overridden (it can't be), it is virtual in the sense that a decision can be made to run it at runtime. Consider the following example which builds on your own:
interface Foo { fun qux(fn: () -> Unit) } open class Bar : Foo { final override inline fun qux(fn: () -> Unit){TODO()} } class Baz : Foo { override fun qux(fn: () -> Unit) = TODO() } fun main() { var foo: Foo = Bar() foo.qux { } // calls Bar.qux foo = Baz() foo.qux { } // calls Foo.qux }
Here, Bar.qux
is invoked initially, but Baz.qux
is invoked the second time. So, not every call can be inlined. So why is this a warning and not a compiler error, like when we declare an open fun
with the inline
modifier? Consider the following:
val bar: Bar = Bar() bar.qux { }
In this case, the compiler can safely inline all calls to qux
on the variable bar
because it's declared as a Bar
. Even if the class is open as in your example, since the method itself is final
, any derived type will always use exactly that qux
. So this statement,
In the example above, when I invoke bar.qux(), the compiler can ensure that only this particular implementation will be used, and can safely inlined.
is true only when the compiler statically knows the type of bar
to be an actual Bar
. It's an error when it's open
because none of them can be inlined which definitely isn't the desired behavior, it's a warning when it's an override because only some of them can be inlined, which might not be the desired behavior.
This example is available at play.kotlinlang.org
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With