Hi everyone :wave: - not sure if this is the right...
# android
a
Hi everyone 👋 - not sure if this is the right channel, please feel free to redirect me if there’s a better one. I recently raised a patch that reduced our APK size by ~350KB, and I’d like some feedback on the safety of the change and better ways to validate it. Change details • Problem: Kotlin generates internal null-safety checks and assertions (
kotlin.jvm.internal.Intrinsics
calls). These account for ~2% of our APK size. • Solution: Added ProGuard
-assumenosideeffects
rules to remove these internal assertion methods (
checkNotNull
,
checkParameterIsNotNull
, etc.). • Effect: Functionality remains the same; only runtime safety checks are stripped out. • Trade-offs (which we’re okay with): ◦ Crash stack traces may lose some detail ◦ Some Kotlin-generated safety information from
Intrinsics.java
will be missing Project context • Codebase: ~97% Kotlin, ~3% Java (20+ files). Concerns • Kotlin → Kotlin calls: Should be safe since nullability contracts are enforced at compile time. • Java → Kotlin calls: Potential risk, since a Kotlin method expecting non-null could be called with a nullable from Java. Current approach • We’re reviewing and testing all Java → Kotlin call sites. • Running automation suite + manual QA for validation. My questions 1. How safe is this approach in practice? Are there pitfalls we might be missing? 2. Is there a more automated / systematic way (beyond manual inspection + tests) to gain confidence that removing these null-safety checks won’t cause issues in production? Would love to hear if anyone has tackled this before, or has suggestions for tooling / strategies to improve our conviction here. 🙏
p
I believe what most runtime safety checks do is just throwing an exception, which is far from good either. On the other hand I wouldn't trade stacktrace details for ~350KB. These days App size is not a problem anymore. Unless we talk in the order of ~50+MB.
2
e
it's not just a matter of stack traces, the whole program behavior may be different
Copy code
// Java
foo(null)
Copy code
// Kotlin
fun foo(input: String) {
    println(input) 
    GlobalScope.launch {
        theMissiles()
    }
}
there's also cases in which a null check in pure Kotlin could be missed by an unchecked cast in generic code
Copy code
fun <T> foo(input: T?): T = input as T
fun bar(input: String?): String = foo(input) 
bar(null)
of course you wouldn't intentionally write that but