jimn
08/03/2021, 8:57 PM#!kotlin
fun logDebug(debugTxt: () -> String) {
try {
assert(false, debugTxt)
} catch (a: AssertionError) {
System.err.println(debugTxt())
}
}
@ExperimentalContracts
inline fun <T> T.debug(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
try { assert(false) } catch (a: AssertionError) {
block(this)
}
return this
}
ephemient
08/03/2021, 11:21 PMassert
desugars to a runtime test on a static $assertionsDisabled
field: https://www.benf.org/other/cfr/how-is-assert-implemented.htmlephemient
08/03/2021, 11:25 PMjimn
08/03/2021, 11:50 PMjimn
08/03/2021, 11:54 PMjimn
08/04/2021, 12:00 AMephemient
08/04/2021, 2:31 AMclass Foo {
fun logDebug(debugTxt: () -> String) {
if (!`$assertionsDisabled`) System.err.println(debugTxt())
}
companion object {
@[JvmSynthetic JvmField] private val `$assertionsDisabled` = Foo::class.java.desiredAssertionStatus()
}
}
would be equivalent, without the Throwable
overhead, at least on JVMjimn
08/04/2021, 3:44 AMjimn
08/04/2021, 3:57 AMephemient
08/04/2021, 5:20 AMassert
) it's also very typical to use a regular code condition structured in a way such that the JIT can hopefully optimize it outephemient
08/04/2021, 5:24 AM#[cfg(...)]
, or Go does with its // +build
, or #if
in C/C++, etc. - but clearly Kotlin decided to go with multiple sourcesets with various `expect`/`actual` declarations instead