Default Arguments
Overview
While both Kotlin and Swift support default arguments for functions, the same is not true for Objective-C. As a result, all Kotlin functions are exported without the default arguments.
Another problem is that Kotlin and Swift have some significant semantic differences regarding default arguments.
Kotlin's default arguments can access the values of previous function parameters and the this
expression (which is self
in Swift).
Neither is possible in Swift because the default arguments are evaluated in isolation, with access only to the global scope.
Because of these fundamental differences, it's impossible to simply generate Swift functions with default arguments. To work around this issue, SKIE instead generates Kotlin overloads that simulate the semantics of a function with default arguments.
The current implementation of the default arguments is considered deprecated. The problem is that when this feature is overused, it can create a non-negligible overhead due to the number of generated functions. Additionally, it is not fully compatible with the library caching and incremental compilation (see Limitations for more details).
As a temporary solution, the default arguments are disabled by default, with the intention that they are enabled only when needed using the Annotation configuration. We plan to eventually reimplement this feature using a different approach that does not have these limitations.
Example
Let's take a data class:
data class User(
val name: String,
val age: Int,
)
Kotlin's data classes have an automatically generated method named copy
that creates a new instance of the data class with some values modified.
For our User
data class, the method can be written as:
fun User.copy(name: String = this.name, age: Int = this.age) = User(name, age)
Without SKIE, the copy
method is exposed to Swift under the following signature: User.doCopy(name:age:)
due to a naming collision with an Objective-C method named copy
.
Since Swift cannot use Kotlin default arguments, all parameters must be provided, which defeats the purpose of the Kotlin copy method.
SKIE generates additional Kotlin overloads that are visible from Swift under the following signatures:
User.doCopy()
User.doCopy(name:)
User.doCopy(age:)
These overloads (plus the original User.doCopy(name:age:)
method) allow Swift to call the copy
method as if the default arguments were directly supported.
Limitations
This approach to default arguments is fully transparent from Swift, but it does have some significant drawbacks:
- It does not support interface methods (all other types of functions are supported, including interface extensions).
- The number of generated overloads is
O(2^n)
, where n is the number of default arguments (not all parameters). - This feature is not compatible with Kotlin native caching and incremental compilation.
Since generating an exponential number of functions is not practical, the number of supported default arguments is limited to 5. Therefore, at most 31 additional functions will be generated per function with default arguments. If a function has more than 5 default arguments, SKIE will not generate any extra functions. But even with this artificial limit, the number of generated functions can be significant in projects with a lot of functions with default arguments.
Another problem is that this feature does not support the Kotlin library caching and incremental compilation. More precisely, the library caching is supported by not generating overloads for functions from 3rd party libraries. SKIE has a configuration to enable the default arguments even for functions from 3rd party libraries. However, be aware that enabling this configuration will disable the Kotlin library caching.
Migration and Compatibility
This feature should not introduce any breaking changes.