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.
On the JVM you should use StackWalker, not a full exception.
https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/lang/StackWalker.html
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?
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