4

Inspired by this question, I was thinking about how could one inline the receiver parameter of an extension function? In theory, like this:

inline fun <T> not(crossinline predicate : (T) -> Boolean)
    = { e : T -> !predicate(e) }

Just that predicate becomes our receiver function:

operator inline fun <T> ((T) -> Boolean).not()
    = { e : T -> !this(e) }

Now, for the above code, I'd expect the compiler to complain that it needs crossinline; however, I get the following warning:

Warning: Expected performance impact of inlining public inline operator fun <T> ((T) -> Boolean).not(): (T) -> Boolean is insignificant. Inlining works best for functions with parameters of functional types

This lets me believe that the compiler is not inlining the receiver of that function. Adding inline or crossinline only produces syntax errors.

Not being able to inline the second function decreases the performance over the first one.

Is there any way to tell the compiler to inline that receiver parameter?

msrd0
  • 7,816
  • 9
  • 47
  • 82
  • initially I just wanted to answer that only functions with lambda parameters are inlined... however as, at least in Java, both functions are actually becoming static methods under the hood and probably just look the same, I would have expected the same too... that a `crossinline` is also possible on the second... but maybe that's only the case for Java and in other languages this isn't the case? – Roland Aug 28 '18 at 13:54
  • @Roland Inlining is not supported by the java compiler. If a function is marked as `inline`, it's lambda parameters are only inlined when you call it from Kotlin with a lambda that the compiler can inline. However, the _receiver parameter_ is a parameter with special syntax and special treatment, but I don't see a reason why the compiler couldn't inline it – msrd0 Aug 28 '18 at 13:57
  • I know... I rather meant what the extension function will translate too... it's basically just the same... That's also the reason why you will get a JVM name clash if you implement both methods. – Roland Aug 28 '18 at 13:59
  • @Roland You are right, both translate to `public static final kotlin.jvm.functions.Function1 not(kotlin.jvm.functions.Function1 super T, java.lang.Boolean>);`. However this doesn't really matter as the translated jvm signature has no inlining information at all (and don't forget kotlin can also be compiled to javascript) – msrd0 Aug 28 '18 at 14:07
  • Yeah... I think my English is not as good as I hoped it to be (or I am too tired) ;-) regarding the other languages, e.g. javascript: I tried to say that in the first comment... obviously, the comment didn't arrive. :-) – Roland Aug 28 '18 at 14:09
  • what I wanted to say: on the JVM they look the same so I would have expected that they are also considered the same on Kotlin... but maybe due to the support for other languages this isn't the case... maybe now it's clearer what I mean? – Roland Aug 28 '18 at 14:11

1 Answers1

1

This is tracked in https://youtrack.jetbrains.com/issue/KT-5837, but doesn't seem to be actively worked on :( I actually just suggested supporting noinline/crossinline hoping that's the main reason receiver isn't inlined.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487