https://kotlinlang.org logo
Title
g

gildor

06/30/2017, 10:28 AM
Just override with default value instead set it in
init
block
interface MyInterface {
    var a: String
}

class ClassA : MyInterface {
    override var a = ""
}
k

kobiburnley

06/30/2017, 10:37 AM
gildor: What I'm trying to say is that as opposed to methods, interface's members always must be overridden. I'm trying to understand why is that
In other words: Why default members (and constructors) are not possible, but default methods are
g

gildor

06/30/2017, 10:40 AM
because interface
interface MyInterface {
    var a: String
}
is compiled to equivalent of Java interface:
interface MyInterface {
    String getA();
    String setA();
}
So now client must override it. To behave as property this interface require also field to save value somewhere. It depends on you how this property should behave
Because default methods cannot hold any state, it’s stateless pease of code. But class field is a state and it’s impossible to keep state in interfaces
If you need default state you can just use class instead interface or delegate with default implementation
interface MyInterface {
    var a: String
}

class DefaultState : MyInterface {
    override var a = ""
}

class ClassA : MyInterface by DefaultState() {
    init {
        //You have an access to `a` without override
        val default = a == ""
    }
}
k

kobiburnley

06/30/2017, 10:50 AM
Cool I'll check it 🙂
It's a quite satisfying solution, although there are still annoying aspects. For example, a delegation class must override all interface members, meaning, in order to have partial default implementation, you should start splitting your interface to multiple interfaces and that's not ideal. At the bottom line, if members compile to a get/set methods, and interface methods may have implementation - there is no reason an interface will not be able to implement default get/set for a member.
g

gildor

06/30/2017, 1:32 PM
But you able to add default getter and setter to interface
interface MyInterface {
    var a: String
        get() = ""
        set(value) = TODO()
}

class SomeImpl : MyInterface
or even better replace
var
with
val
, because child class can replace var with val itself:
interface MyInterface {
    val a: String
        get() = ""
}

class SomeImpl : MyInterface
but to be honest this code smells. Just curious what is your case?
delegation class must override all interface members
Actually, from architecture point of view I see no problem with it. You can create partially implemented abstract class and then extend it and implement all other methods and provide resulting class as delegate to an another class (ClassA in you example). Only difference that you have now is separated implementation: 2 classes instead 1 (but it’s not a problem in Kotlin to have them in the same file). But it’s even better, because now you have better code separation and easy replace delegate implementation without changing target class
k

kobiburnley

07/01/2017, 9:18 AM
As I see it the big problem with delegation class is that it creates a new scope. For example:
interface A {
    var mem: String

    fun f() {
        print("A.f()")
    }
}

class DefaultA : A {
    override var mem: String = ""
        set(value) {
            field = value
            f()
        }
}

class B : A by DefaultA() {
    override fun f() {
        print("B.f()")
    }
}

fun main(args: Array<String>) {
    val b = B()
    b.mem = "a"
}
Will print "A.f()" although class B overrides it - because the setter of "mem" is called in the scope of "DefaultA"
Delegation class is a pretty good solution to my use-case, although I think default setters, getters, and constructors should be allowed in interfaces. There must be a reason it's not allowed in Kotlin, but I'm still looking for the answer why. The compiler can enforce a class to override a setter/getter/constructor if there are collisions of multiple inherited interfaces
g

gildor

07/01/2017, 11:31 AM
I don’t understand what do you mean about “default setters, getters, and constructors should be allowed in interfaces”. Default getter and setters supported by Kotlin. I showed example above But of course not Constructors, There is no multiple inheritance in JVM by default, and if your language emulates that you still have a lot of problems, especially with Java interoperability.
compiler can enforce a class to override
What do you mean? Compiler force all clients to override all not implemented methods otherwise just throw exception
And you example with DefaultA is completely correct for me. I mean it’s the only possible behavior. Delegate of course cannot and shouldn’t have an access to outer class, like any class/method that called inside other class have no access to parent, otherwise it’s completely break incapsulation of any code. In this example setter have access only to current class, as any other code. Delegates called “delegates” because there is no inheritance, you just use public API of an another class, delegating calls. Looks like you trying to achive multiple inheritance, but there is no such think in Kotlin or Java. Maybe if you describe you case I, or someone else, could help with architecture of that
k

kobiburnley

07/01/2017, 6:20 PM
In your example interfaces setters and getters are very naive:
interface MyInterface {
    var a: String
        get() = ""
        set(value) = TODO()
}
Try to add custom setter using a backing field - you can't.
What I want to achieve is be able to add setter and getter implementation in interfaces. Refactoring my previous example (this code will not compile, but if it would it will print "B.f()"):
interface A {
    var mem: String = ""
        set(value) {
            field = value
            f()
        }
    
    fun f() {
        print("A.f()")
    }
}

class B : A {
    override fun f() {
        print("B.f()")
    }
}

fun main(args: Array<String>) {
    val b = B()
    b.mem = "a"
}
From architecture point of view there's always something that can be done. We did it in Java too (delegation classes / delegating a method to a static function). But I'm looking for ease of use, readability, and reduce of verbosity .