I don’t think there is much that you can do. Basically, what you’re saying is that exec can have zero or one parameter of unknown type. If you knew the type, you could specify a default value.
How would you be calling exec of type Foo in your example? The closest I have come to what you want would be this:
interface UseCase<T, V> {
fun exec(input: T? = null): V
}
class Foo : UseCase<Any, Nothing> {
override fun exec(input: Any?): Nothing {
throw UnsupportedOperationException()
}
}
class Bar : UseCase<String?, String> {
override fun exec(input: String?): String {
throw UnsupportedOperationException()
}
}
fun main(args: Array<String>) {
val bar = Bar()
bar.exec("Hello world!")
val foo = Foo()
foo.exec()
}
interface UseCase<T, V> {
fun exec(input: T): V
}
class Foo : UseCase<Unit, String> {
override fun exec(input: Unit): String {
//Go get the string from DB
return "some string from DB"
}
}
fun test(){
val foo = Foo()
val value = foo.exec(Unit)
//do something with value
//compile error:
//val value2 = foo.exec()
}
Btw using Nothing forces you to write Nothing as return type.
The reason why it’s possible to omit Unit as a return type but not as a parameter type is that a function always has exactly one return value but can have an arbitrary number of parameters. If you wanted to allow to omit Unit as a parameter type, you’d quickly run into all sorts of ambiguities with overloaded methods. (E.g. what if your class also implements an interface which has a no-argument exec method? What does override fun exec actually override?)
And the amount of inconvenience that could be avoided by adding all this complexity is very minor.