Rey (Kingg22)
03/03/2026, 12:15 AMextension_api.json, ~1000 classes, ~25+ functions per class)
Trying to validate my current architectural decisions before we go too far.
A few questions, any partial answers appreciated:
1. Extension functions on companion objects vs members inside companion. We're generating static-style factory methods. Plan is to emit a bare companion object and put all static methods as top-level fun ClassName.Companion.method() in separate files rather than inside the companion body. Is this actually better for DCE / IR pipeline, or equivalent? Is a companion object treated as a separate singleton class in the IR, meaning members inside it get dragged together regardless of usage?
2. Properties without backing fields. We're generating computed properties (getter/setter, value is a cinterop call). From the compiler's perspective, is a property with no backing field essentially equivalent to a plain function, or is there any overhead in the IR / metadata?
3. What's "huge" for a class? Is there a rough threshold (methods, lines, IR nodes) where a single class becomes costly for the compiler or linker? We're splitting non-virtual methods into extension functions in separate files specifically to avoid this โ is that the right mitigation, or is file count / declaration count per file also a factor?
4. Kotlin enum vs value class for C-style enums. We need to represent Godot enums (C-style, backed by a long constant). Is a Kotlin enum class with a val value: Long meaningfully worse than a value class wrapping Long, in terms of flatten/unboxed memory representation and compiler output? Does the compiler eliminate the wrapper in the value class case always?
5. Top-level declarations โ can a file also become "huge"? If we put, say, 200 top-level functions in a single file (no top-level state/properties), is each declaration treated individually by the compiler/linker, or does the file boundary matter at all for IR or compilation cost?
6. Kotlin Scripting + Kotlin/Native. Obvious one, but just to confirm: Kotlin Scripting can't currently be used with Kotlin/Native, right? Is there any roadmap or tracking issue for that?
Thanks in advance, happy coding! kodee happy
PS. Currently with 65 files compiles fine < 30s (debug type)rnett
03/03/2026, 3:28 AMIvan Kylchik
03/03/2026, 2:06 PMIs this actually better for DCE / IR pipeline, or equivalentI would say it is equivalent in terms of DCE. When we link a class, we load everything that is inside and when we link top-level function, then only this function is loaded. But in the end, DCE will optimize both cases the same way (we will remove everything that is unused).
Is a companion object treated as a separate singleton class in the IR, meaning members inside it get dragged together regardless of usage?Yes. Companion objects are compiled as a separate classes with all the methods inside. Unless it is JVM and method is marked with
@JvmStatic.
I am not sure how you are going to use it, but generally I would recommend putting everything inside companion object. Extensions on companion should be used if you have no control over companion itself (for example, it is located in the lib). With extensions you must import every function separately and this creates unnecessary noise.
Also please take a look and this document about improving companions. This should help you, but it will take some time to finalize the design and implement it.
2.
From the compiler's perspective, is a property with no backing field essentially equivalent to a plain function, or is there any overhead in the IR / metadata?If a property is public, then you will see it in metadata. I am not sure I can call it "overhead". You can inspect metadata of klib by using klib tool. It is located in the Kotlin compiler
kotlin-native/klib/src/org/jetbrains/kotlin/cli/klib/main.kt. Build compiler by calling gw dist and the check the tool kotlin-native/dist/bin/klib --help
3.
I would recommend for you to experiment with it (and post there the results ๐). Personally, I don't know. I would say that only the amount (and size) of functions is important, but no concrete numbers.
4.
I would say that value class is better for performance, but more or less the same for memory footprint. There is an old idea to be able to compile/optimize enums using value classes but we don't have strong use cases to continue. You can describe your problem in more details and we will take a look if this optimization actually help in your case.
5.
I would say that from compiler perspective 200 declaration inside a file and inside a class is the same thing. But you can easily test it by creating such artificial file and running Native compiler on it kotlin-native/dist/bin/kotlinc-native hello.kt -p library.
6.
Kotlin Scripting can't currently be used with Kotlin/Native, right?Only JVM.
Rey (Kingg22)
03/03/2026, 2:19 PMRey (Kingg22)
03/03/2026, 2:27 PMenum class because pattern matching is a better experience for Kotlin devs and aligns well with how other Godot language bindings feel. However I'm aware the object overhead is unnecessary at runtime, it's purely a compile-time/API convenience, not something I need in the actual native output.
I evaluated value class as an alternative, but without compiler-supported pattern matching (the way Rust handles it, for example) I'd have to implement that manually, which defeats the purpose. So for now enum class stays, the DX wins over the marginal runtime cost.
Just wanted to close the loop on that point in case it's useful context for the potential enum+value class optimization you mentioned. Thanks blob smile happyRey (Kingg22)
04/06/2026, 5:07 AM