Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract member cannot be access directly: Kotlin

Tags:

java

kotlin

I have interface A with implemented method t()

interface A{
    fun t() : String{
        return "A"
    }
}

And abstract class B

abstract class B : A{
     override abstract fun t(): String
}

And one class C

open class C: A, B(){
    override fun t(): String {
        //return super<A>.t() // getting error
        return super.t() //getting error here 
    }
}

I want to call interface function t() but its giving me error Abstract member cannot be access directly

If I remove implementation of A from B its working.

can anyone explain why?

like image 285
Pratik Popat Avatar asked Mar 09 '23 17:03

Pratik Popat


2 Answers

There is no reference in kotlin, but the Method Invocation Expression TypeName.super. [TypeArguments] Identifier ( [ArgumentList] ) in java is described exactly in JLS-15.12.3:

Note: interface in here is a class/ an interface.

If TypeName denotes an interface, let T be the type declaration immediately enclosing the method invocation. A compile-time error occurs if there exists a method, distinct from the compile-time declaration, that overrides (§9.4.1) the compile-time declaration from a direct superclass or direct superinterface of T.

In the case that a superinterface (class B) overrides a method declared in a grandparent interface (interface A), this rule prevents the child interface from "skipping" the override by simply adding the grandparent to its list of direct superinterfaces. The appropriate way to access functionality of a grandparent is through the direct superinterface (class B), and only if that interface chooses to expose the desired behavior. (Alternately, the developer is free to define his own additional superinterface that exposes the desired behavior with a super method invocation.)

So even if the t() is a concrete method in class B, it also failed in compile time, for example:

interface A {
    fun t() = "A"
}

abstract class B : A {
    override fun t() = "B"
}

class C : A, B() {
    //                      v--- error
    override fun t()= super<A>.t();

    //              v--- ok
    fun ok()= super<B>.t();

}

Following the rule of the JLS-15.12.3 , you also can't access grandfather interface A if you don't let class C implements A directly, for example:

//       v-- grandparent interface A is removed from class C  
class C : B() {    
    //                       v--- can't access the grandparent interface A
    override fun t() = super<A>.t(); 
}

An abstract superinterface can re-declare a concrete method in its grandparent interface to an abstract method. but you must implements the abstract method in child class, for example:

interface GrandParent {
    fun foo() = "bar";
}

interface Parent : GrandParent {
    override fun foo(): String;
}

//     v--- must implements abstract foo() method in Parent interface
class Child : Parent;
like image 104
holi-java Avatar answered Mar 11 '23 06:03

holi-java


When class B 'called' the interface A, it was supposed to implement the function in the interface but didn't do that. Instead, it 'promised' (by using the abstract keyword) to leave that implementation to any class that inherits it, to which interface A agreed. Now when class C came in, it 'called' both function B and interface A and overrode a function t() (a function both interface A and function B have). Now, the question is, which of function t() is being overridden? You can't do that and that is why you have your error.

Or using another analogy, class B is owing with interface A. If class B had paid interface A, then it can help class C settle it's debt with interface A, like this:

interface A{
    fun t():String{
        return "A"
    }
}

abstract class B :A{
    override fun t():String{
        return "potato"
    }
}

open class C:  A, B(){
    override fun t(): String {
     return super<B>.t()
    }

But since that's not the case, class C has to settle it's own debt with interface A like this:

open class C: A {
    override fun t(): String {
     return super.t()
    }

}

Or help class B pay his, like this:

open class C:  B(){
    override fun t(): String {
     return super.t()
    }

}

It can't do both because that will be creating two functions with the same signature. Hope this analogy helped you understand.

like image 40
Alf Moh Avatar answered Mar 11 '23 05:03

Alf Moh