Static duck-typing for Kotlin.
Filling the gap of Kotlin ducktyping without risking runtime-errors.
Sometimes this is also known as "structural typing".
Write some code using interfaces, for example:
interface Duck {
fun quack()
}
object Sea {
fun enter( duck:Duck ) {
duck.quack()
}
}
Create or include any classes which ducktype the interfaces.
For example:
class ActualDuck {
fun quack() = println( "quack" )
}
class ActualFrog {
fun quack() = println( "quaak" )
fun borg() = println( "borg" )
}
Call the code-generator like
CodeGenerator.createExtensionMethods("outputfile.kt")
.
Use ducktyped classes as if they implemented the interfaces:
Sea.enter( ActualDuck() )
Sea.enter( ActualFrog() )
The code-generator searches for pairs of classes and interfaces where the class implements all methods of the interface. Based on this knowledge he scans all existing classes and creates extension-methods for those methods where types can be ducked. These generated extension-methods enable ducking by anonymous wrapper-objects.
- Use a Go-like interface system :D
- Compared to other languages like for example Python or Go, DucKtypes still allows for normal static type-checking using interfaces. None of your code or code using a ducKtyped library automatically ducks any types into other interfaces "without permission". So Kotlin stays of course type-safe. Only by importing the extension-methods, duck-typing is enabled (use ALT+ENTER or CMD+ENTER in IntelliJ IDEA).
- find classes automatically
- integrate code-generation into gradle build process
solve conflicting-overload situations (see known problems)- improved configurability (specify classes, packages and interfaces and/or interface-packages which are to be ducktyped)
- use KotlinPoet (was not available previously) instead of string concatenation.
- JavaDoc is not copied to generated extension-methods (yet?)
- The codegenerator may generate
conflicting overloads
which are quite logical because ducktyping is a very loose concept which leads to methods accepting more types and thus maybe accepting the same types.
Compared to static typing, this error message corresponds to Kotlin'soverload resoultion ambiguity
like in this example:The current solution is to use the annotation @Duckable for method parameters and the compiler-parameterinterface A interface B object Both : A,B object Receiver { fun doSth( a: A ){} fun doSth( b: B ){} } fun callIt() { Receiver.doSth(Both) // overload resoultion ambiguity: it is not clear which method is correct }
reguireAnnotations=true
Other suggestions for solutions are welcome.