What is the purpose of an internal interface?

I do not understand when I would an internal interface as they currently exist in Kotlin. While the interface itself is internal, it still forces the implementations of its methods to be public. This means that in order to use the internal interface you still need to expose the functions within them, so I do not understand the use of this feature. It is not safe to use when you want to keep methods internal, so it does not offer any additional protection to a public interface. Is there something I am missing?

Visibility of a class/type and visibility of members are two much different things. Internal interface means that only your own module can access it, but its methods are available to your whole module.

3 Likes

I understand that they are different; I just don’t see how it does anything useful. The purpose of restricting visibility is to create an abstraction barrier. Internal interfaces, despite being internal, do not create a stronger abstraction barrier than a public interface. I don’t see a circumstance where I would want public members but an internal interface. If the client can access the implementation of the interface’s functions, there is no additional safety that is guaranteed by restricting access to the interface itself.

What about accessing your interfaces and classes from outside your module? If you create some kind of a library, you would like to hide your internal classes to be not accessible by users of your lib. This is what internal do.

1 Like

Yes, I am currently working on a library, and the behavior of internal interfaces prompted this question. I would like to have an internal interface but only because the operations within it would be unsafe for the client to call. By hiding the type but exposing the operations, we don’t reduce the accessibility of the unsafe operations. I’m wondering if you had a more specific example of an interface whose operations are all safe for the client to call but whose type would be unsafe for the client to access.

Honestly, I’m a little confused :slight_smile: If the class/interface is internal, so it is entirely hidden from users of your lib, then how they could access its members?

For example, this would not compile:

internal interface MyInterface {
    fun unsafeOperation()
}

class MyClass: MyInterface {
    internal override fun unsafeOperation() {
        //Implementation
    }
}

It gives the error: Cannot weaken access privilege ‘public’ for ‘unsafeOperation’ in ‘MyInterface’

It will only compile if I declare the implementation of unsafeOperation() as public. It is not at al the behavior I would expect, but that’s what the compiler demands. All members of an interface must be public (I assume to maintain interoperability with Java, which is fine), so then what is the point of even allowing the internal modifier on an interface.

Ahh, ok, that makes sense. Personally, I don’t like internal visibility on members, because for me member visibility is more like inside-class vs outside-class. But if Kotlin allows internal on members, then maybe it should also allow internal on interface members, I agree. EDIT: Or even better, members of internal interfaces should be allowed to be internal in implementations.

Anyway, answering your main question: for me internal interfaces are needed, because in most cases I implement internal interfaces by internal classes and then the problem you described doesn’t exist.

1 Like

Oh that makes sense as a use-case then! Thank you!

Interfaces are created to describe the requirements of the methods you pass them to. An internal interface is for internal requirements. If an interface does not appear in the signatures of any public methods, constructors, or properties, then there is no reason for that interface to be public.

This is a useful thing, but it is not entirely what you want. If there are operations that are unsafe for a client to call, then they should not be public methods on any type that the client can see – no public type should implement the internal interface.

That may mean that you need to change your design a bit. You probably have classes that you are passing out to clients right now that implement this internal interface. These should be replaced with abstract classes or interfaces that do not implement the internal interface. Then the clients just don’t have any object with those unsafe methods declared on it.

1 Like

That makes sense, thank you. Somewhat annoying that I need to now wrap everything in an additional layer of abstraction.

You can find some real-life examples in Kotlin libraries. For example, it can be an internal marker that an exposed implementation conforms to some internal contract, see

It might also have contained some public methods, without them being exposed through any public API surface.

It can also be a part of a completely internal hierarchy of classes and interface, that are not exposed at all

2 Likes