Delegacja funkcji – suplement

Na wykopie pod linkiem do wczorajszego wpisu padło pytanie:

A jak rozwiązywane są konflikty, gdy np rozszerzasz klasę, która ma tę samą nazwę metody co delegowany interface?

Najpierw rzućmy okiem na zachowanie „gołej” Javy:

Listing 1. Java, a metody o takiej samej nazwie

public class App {

	public static void main(String[] args) {
		C c = new SubC();
		c.m();

		SubC subC = new SubC();
		subC.m();

		I i = new SubC();
		i.m();
	}
}


interface I{

	default void m(){
		System.out.println("From I");
	}
}


class C{

	public void m(){
		System.out.println("From C");
	}

}

class SubC extends C implements I{

	@Override
	public void m() {
		super.m();
		System.out.println("From SubC");
	}
}

Ładnie się skompilowało i wypisuje:

Listing 2. Efekty działania

From C
From SubC
From C
From SubC
From C
From SubC

Jednak ten kod nie jest dokładnie tym samym czym kod w Kotlinie. Tu mamy do czynienia z dziedziczeniem i implementacją interfejsu, a nie z delegatami. Jednak możemy wnioskować, że Kotlin powinien zachować się podobnie. Zobaczmy:

Listing 3. Przesłanianie nazw z delegatem

interface I {
    fun m(){
        println("From I") 
    }
}

open class C {
    open fun m() {
        println("From C")
    }
}

class D : I {
    override fun m() {
        println("From D")
    }
}

class SubC(d: D) : C(), I by d {

}

To się nie skompiluje, ponieważ kompilator nie może wybrać implementacji m z pomiędzy C.m i I.m. Wynika to z zaimplementowania metody I.m. Jeżeli usuniemy implementację:

Listing 4. Brak implementacji I.m

interface I {
    fun m()
}

open class C {
    open fun m() {
        println("From C")
    }
}

class D : I {
    override fun m() {
        println("From D")
    }
}

class SubC(d: D) : C(), I by d {

}

Wszystko pójdzie zgodnie z planem i wypisywane będzie From D. Innym rozwiązaniem jest implementacja spornej metody, ale wtedy tracimy „urok” delegatów, bo musimy je samodzielnie skrobać.

Napisz odpowiedź

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax