JakeWharton/cite

Support getting call site position of a function

mzgreen opened this issue · 8 comments

Consider this example:

fun test(lineNumber: Int = __LINE__) {
  println("$lineNumber")
}

test()
test()

It prints the same value twice. This means that it's impossible to get a call site position of a function using Cite. It's supported in Swift.

Did you try inline fun test(lineNumber: Int = __LINE__)?

Yeah, inline doesn't work too. I think the __LINE__ is replaced with a line number at the moment when the test function is declared. the compiler detects the __LINE__ property reference and replaces it with a line number. Then when the function is called, the default parameter is already set to a constant integer line number value. And adding inline doesn't change anything, because the bytecode of the function (with the line number already set) is just copied to the callsite and the effect is the same as without using inline.

The thing is that visitCall currently just analyzes the property accesses: https://github.com/JakeWharton/cite/blob/trunk/cite-kotlin-plugin/src/main/kotlin/com/jakewharton/cite/plugin/kotlin/CiteElementTransformer.kt#L128

This would need to be changed to take into account actual function calls, in the example above it means that it should check for the test() function call, and replace the value of the argument with the line number at the place where the function is called.

I'm really hesitant about this because it means that all downstream modules would need to have the Kotlin compiler plugin (or Gradle plugin) applied. That is very hard to guarantee, and would be a huge foot-gun.

Yes, I agree that this is a drawback. But on the other hand, Cite in its current form is quite static. It replaces the line numbers statically, you can write these numbers yourself manually when writing the code. Sure it'll be hard to maintain such thing and update the values all the time but what I want to say is that such static behavior is quite limiting. What use cases do you see for it without supporting call site positions? You can't for example write a log method that logs a line number of the call site, which is a common use case in Swift.

On the JVM, you can actually log a call-site line number without any plugin support. One way of doing this is throwing an exception, then examine its stack trace and extract call-site information. Some logging frameworks offer such functionality. I'm not saying this is pretty or efficient, but it's possible.

Logging was just one of the examples where call site positions may be useful. There are lots of cool stuff you could build with it. For example you could create a remember {} that does positional memoization like Compose but without Compose.
If I understand correctly there are no plans for supporting that in Cite, am I right?

vlsi commented

I'm really hesitant about this because it means that all downstream modules would need to have the Kotlin compiler plugin (or Gradle plugin) applied

What if __LINE__ property returned 0 when compiler plugin was not present?
Then it won't fail the runtime for those who omit the plugin, while it would allow having compile-time line numbers as described in the issue.

In other words, the plugin could detect default argument __LINE__ value, and pass the line number