2
votes

I would like to use a default value for a function parameter in a class implementing an interface, like this:

interface FileStoreService {
    fun storeFile(path: String, payload: InputStream, type: MediaType, replace: Boolean = true)
}
class LocalFileStoreService : FileStoreService {

    override fun storeFile(path: String, payload: InputStream, type: MediaType, replace: Boolean /* ?? */) {
        // ....
    }
}

Now here is what compiles and here is what doesn't compile:

KO: An overriding function is not allowed to specify default values for its parameters

class LocalFileStoreService : FileStoreService {

    override fun storeFile(path: String, payload: InputStream, type: MediaType, replace: Boolean = true) {
        // ....
    }
}

KO: Class 'LocalFileStoreService' is not abstract and does not implement abstract member public abstract fun storeFile(path: String, payload: InputStream, type: MediaType): Unit defined in fqn...FileStoreService

class LocalFileStoreService : FileStoreService {

    override fun storeFile(path: String, payload: InputStream, type: MediaType, replace: Boolean) {
        // ....
    }
}

OK:

class LocalFileStoreService : FileStoreService {

    override fun storeFile(path: String, payload: InputStream, type: MediaType) {
        storeFile(path, payload, type, true)
    }

    override fun storeFile(path: String, payload: InputStream, type: MediaType, replace: Boolean) {
        // ....
    }
}

Is this the expected behaviour? Is there a better way to manage default parameter values in interfaces?

1
Just an idea to improve the question: Make your example truly minimal by using only 1 or 2 parameters and don't use Java specific types.Willi Mentzel

1 Answers

1
votes

What you describe is odd, because by trying to reproduce it with Kotlin 1.4.20, I do not see the same behaviour.

Below code is working fine:

interface Test {
    fun test(p1: String, p2: Boolean = true)
}

class TestImpl : Test {
    // below commented function breaks compilation
    //override fun test(p1: String) = println("That's odd... received: $p1")

    // You cannot overwrite default value, that would break interface contract
    override fun test(p1: String, p2: Boolean) = println("It works ! Received: $p1 and $p2")
}

fun main() {
    // Default value for second parameter is deduced from interface signature 
    TestImpl().test("Hello")
}

If I uncomment the function without boolean parameter, compilation crashes, because the method does not inherit from the interface.

Generally speaking, if you define default values at interface level, it would be a bad idea to change the default value for a specific implementation, because it would break API contract.

Edit

Note that removing override keyword from commented function would produce valid code, because it becomes a function specific to the implementation. I find such behavior dangerous, though, because the following program:

interface Test {
    fun test(p1: String, p2: Boolean = true)
}

class TestImpl : Test {
    fun test(p1: String) = println("That's odd... received: $p1")
    override fun test(p1: String, p2: Boolean) = println("It works ! Received: $p1 and $p2")
}

fun main() {
    val t : Test = TestImpl()
    t.test("Hello")
    (t as TestImpl).test("Hello")
}

will then produce this output:

It works ! Received: Hello and true
That's odd... received: Hello