Interface method in Kotlin should support protected && internal visibility modifier


#1

As interface in Kotlin can implement method as default, we can not just treat interface as traditional interface which means ‘what you can see from outside the class’. It really like a superclass we can extend from it, and in the interface we select which method to exposed to outside.

Let’s make a sample. I want to expand all my custom view with update data function.As my custom view may extend from different base-view(LinearLayout, FrameLayout, ScrollView, View…),i can not do this thing in the superclass. The best way is implementing an interface like IViewDataUpdater.

interface IViewDataUpdater{
	fun updateData(data: Data){
		if(data.isValid){
			updateDataValid(data)
		} else {
			updateDataInvalid(data)
		}
	}
	
	fun updateDataValid(data: Data)
	
	fun updateDataInvalid(data: Data)
}

But in this sentence, i really don’t want to expose my updateDataValid and updateDataInvalid to outside, updateData is the only method i really expose. So code as below is what i want.

interface IViewDataUpdater{
	fun updateData(data: Data){
		...
	}
	
	protected fun updateDataValid(data: Data)
	
	protected fun updateDataInvalid(data: Data)
}

Maybe the example is not the best scenarios of use, it exactly explain the problem.


Interface internal members support: suggestion
#2

+1


#3

@ohmerhe nice question.+1


#4

In this case you need a helper class with update data logic, interface default method isn’t a work around for multi inheritance and non-public method in Java interface sounds hard.


#5

I know what do you mean, and i do what you say before i use Kotlin.

But i think interface provide default implement for method can bring new develop pattern, and it’s more convenient to expand class capacity and easy to maintenance. Why do not try new pattern?


#6

Primary for JVM compatibility problems.


#7

Generally speaking, “why do not try new pattern?” is not how language design works. Adding a new feature to a language takes a lot of time and resources, so every new feature requires a very strong argument showing what problems it can solve, and why existing solutions for those problems are not adequate. So far I don’t see any convincing argument.

(Note that Java does not support non-public methods in interfaces, so we would need to come up with some kind of special encoding for such methods, which would make Java interoperability more difficult.)


#8

If i can do it, different function modules can be split clearly and i don’t need class like Helper which often need to create relations or bind with it. It also make grouping different modules easily and looks more intuitive.

Of course designing language is hard and complicated, and new feature may cost time and resources, and to any new feature you should be careful. But as a user of Kotlin, i advice my idea from my firsthand experience. if the advice do not break some rules and can bring convenience to coder, i think we can discuss with it.

In consideration of compatibility with java or other things, maybe it’s difficult, you can accept my advice or not, it is just advice. And as i know internal visibility modifier is not supported by Java too.


#9

+1 to this feature.

It is very strange that interfaces can’t have protected methods due to JVM interoperability issues, but do can have private methods.

How are private methods implemented?


#10

For the jdk 6 target private methods are implemented the same way that public methods are. As static methods of an inner class. If your class inherits this, it will generate implementations (if it’s not overridden) for all the “implemented” methods by making them call the static method with the object as the first parameter. Private methods are only accessible inside the inner class so don’t need overriding. Java interfaces at 7 or below don’t allow non-public members (they would not make sense as the only point of implementing a method is to call it and and interface itself can’t do that).
Basically the JVM was designed very closely to Java, as such non-java allowed features are generally forbidden (strangely enough you can use names with characters that are forbidden in java-the-language). JVM Spec 7 specifies that fields must be public static final and methods must be public and abstract and may only have vararg, bridge and synthetic as other attributes.
When targeting JVM 6 or 7 this basically restricts what is possible. Of course it is possible to have compilation-only restrictions such as Kotlin’s internal (which basically just renames the method and adds some attributes in the class file - a jvm must silently ignore attributes not understood). In JVM spec 8 protected visibility is still not allowed.


#11

Yet another instance where Kotlin is held back by arbitrary (?) restrictions in Java. :confused: Package-private resp. module-internal interfaces resp. interface members are a huge help for robust modelling. Arguably, much of the advantage would remain even if only the Kotlin compiler were to honor the restriction. Annotations like @DoNotCall might serve to dissuade external usage from Java.

But I’m only thinking randomly; I’m aware that such an approach would hardly fit with the current paradigm of Kotlin.


#12

Maybe I’m missing something, but isn’t the answer here that you make 2 interfaces. The first is public and just exposes the updateData method with no default implementation. The second extends from it, has the methods you show and is not public and that is the one that implementing classes implement?


#13

You are missing that while you can certainly write that down and the internal interface will indeed be hidden, the implementations of the methods declared in the internal interface will still be public.


#14

Well you could go as far as having the class itself be internal as well and just exposing it through the public interface. This would mean you would need a factory to create the objects. Not sure this approach is for everyone. I normally don’t like the use of factories where they are not totally necessary but this would at least be a workaround.


#15

There is a substantial difference between “default implementation” and “sub-implementation.” Kotlin interfaces aren’t “like a superclass that you can extend from.” If so they would be entirely useless. They are interfaces which have suggested default implementations. But things that are implementations of the Interface aren’t guaranteed to have any particular implementation just because there’s a particular SUGGESTED one, and so there’s no coupling; that’s the entire point of interfaces. Having “this endpoint which can be overridden by anything but only certain things have access to it” does not even make sense on a conceptual level.

If you want functionality that is not exposed, then you want classes. If you want multiple inheritance then you want delegates.


#16

Ah, I did not even think of that, thanks!

Since we can make look factories like constructors in Kotlin, this isn’t too bad:

public interface File {
    val name: String

    companion object {
        private var counter = 0

        operator fun invoke(name: String) : File {
            return FileImpl(counter++, name)
        }
    }
}

internal interface FileInternal: File {
    val id: Int?
}

internal data class FileImpl(
    override val id: Int?,
    override val name: String
) : FileInternal

fun extract(f: File) {
    if ( f is FileInternal ) {
        println(f.id)
    }
}

fun main(args: Array<String>) {
    val f1 = File("Test A")
    val f2 = File("Test B")
    extract(f1)
    extract(f2)
}

I think I could live with this pattern. I would ask, though, why the compiler can’t apply it for me. :slight_smile: