1

I'm trying to make this higher-order Kotlin function:

private inline fun <T> reentrant(entered: ThreadLocal<Boolean>, block: () -> T, enter: (() -> T) -> T) =
    if (entered.get()) block()
    else {
        try {
            entered.set(true)
            enter(block)
        } finally {
            entered.set(false)
        }
    }

To be used like this, for example:

reentrant(fooing, block) { b ->
  try {
    log("Entering a state of foo")
    b()
    // sidenote: while writing this question it dawned on me,
    //           that i could just calll the captured `block` here,
    //           as a workaround
  } finally {
    log("Foo nevermore")
  }
}

However, apparently the construct enter(block) is not allowed (Illegal usage of inline parameter block).

Since everything here is inline, I think it should be technically possible. Is this feature just not supported by the compiler? Or is there a way I can do this after all?

2
  • The error message says "Add noinline modifier to the parameter declaration". If you add this modifier to the block parameter it now compiles. Do you want to avoid this, or is that good enough? Commented Nov 14, 2018 at 10:49
  • Yes that's what I would like to avoid. I did just realize that it's a not a good idea to inline a lambda that's called twice, but I'm still interested in why this is conceptually not possible. Commented Nov 14, 2018 at 10:53

1 Answer 1

1

You get the same error if you do something like val x = block. If you try to decompile that Kotlin into Bytecode the very last error you'll see is:

Trying to access skipped parameter

I think the point is that when you inline something it's no longer an object in the code, so you can't directly refer to it. Obviously just calling the function itself is OK as that's inlined into your calling code.

This is explained in more detail here. When the function parameter is inlined, there is no Function object created. I wonder if in your question what you're implying is: "Why doesn't the compiler inline enter and then inline block into that?" And I guess the reason is that this would assume that all enter does is invoke block. But what if it didn't? What if it wanted to store a reference to it, e.g. in a list of functions to call at some point in future? It couldn't do this, as there's no Function object for it to reference.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.