There is a little discrepancy between visibility of companion class members in a companion owner class. E.g. functions and values declared as protected and inherited by companion object are visible, but nested classes are not. Make these classes visible too can be a useful in some cases:
open class CommonTestDoubles {
/* TODO protected ? */ class CommonClass
protected fun commonFunction() {}
}
class SomeTest {
private companion object : CommonTestDoubles() {
private class PrivateClass
private fun privateFunction() {}
}
fun someTest() {
PrivateClass()
privateFunction()
// 1. Import of the companion object nested class is required.
// 2. Can be confused when importing with AnotherTestDoubles.CommonClass() :
CommonTestDoubles.CommonClass()
commonFunction()
}
}
class SameTest {
private companion object : CommonTestDoubles()
fun sameTest() {
// 1. Import of the companion object nested class is required.
// 2. Can be confused when importing with AnotherTestDoubles.CommonClass() :
CommonTestDoubles.CommonClass()
commonFunction()
}
}
open class AnotherTestDoubles {
/* TODO protected ? */ class CommonClass()
protected fun commonFunction() {}
}
class AnotherTest {
private companion object : AnotherTestDoubles()
fun anotherTest() {
// 1. Import of the companion object nested class is required.
// 2. Can be confused when importing with CommonTestDoubles.CommonClass() :
AnotherTestDoubles.CommonClass()
commonFunction()
}
}
1 Like
Comments
If I’m right, the comments aren’t related to the problem you’re posting…
What the comments describe is intended:
CommonClass should not be accessible without refering to the base class as it isn’t an inner class but a nested class.
So, it’s just a static class which happened to be definined inside another class.
Inner classes are accessible inside the class with the companion object.
This means the references are correct.
The problem:
When a companion-object inherits from another class:
- Its surrounding class gains access to inherited protected functions
- Its surrounding class doesn’t gain access to inherited protected (inline) classes.
While protected/private classes defined inside the companion object itself are accessible by the surrounding class.
Your understanding of the suggestion for improvement is right. Comments simply show places in the code, which can be written safer and shorter with this improvement.
You also say about nested class what “CommonClass should not be accessible without refering to the base class” and this means that a nested class protected visibility modifier effectively is the same as private. And what is surprising for me it is really so in Kotlin:
open class Parent {
protected open class NestedProtectedClass
private open class NestedPrivateClass
}
class Child: Parent() {
// An unexpected compilation error:
// 'public' subclass exposes its 'protected (in Parent)' supertype NestedProtectedClass
class NestedExtendingProtected1: NestedProtectedClass()
// Same compilation error:
// 'public' subclass exposes its 'protected (in Parent)' supertype NestedProtectedClass
class NestedExtendingProtected2: Parent.NestedProtectedClass()
// An expected compilation errors:
// 1. Cannot access 'NestedPrivateClass': it is private in 'Parent'
// 2. 'public' subclass exposes its 'private' supertype NestedPrivateClass
class NestedExtendingPrivate1: NestedPrivateClass() //
// Same compilation errors:
// 1. Cannot access 'NestedPrivateClass': it is private in 'Parent'
// 2. 'public' subclass exposes its 'private' supertype NestedPrivateClass
class NestedExtendingPrivate2: Parent.NestedPrivateClass() //
}
but not in Java:
public class Parent {
static protected class NestedProtectedClass {}
static private class NestedPrivateClass {}
}
class Child extends Parent {
static class NestedExtendingProtected1 extends NestedProtectedClass {}
static class NestedExtendingProtected2 extends Parent.NestedProtectedClass {}
// An expected compilation error:
// Parent.NestedPrivateClass has private access in Parent
static class NestedExtendingPrivate1 extends NestedPrivateClass {}
// Same compilation error:
// Parent.NestedPrivateClass has private access in Parent
static class NestedExtendingPrivate2 extends Parent.NestedPrivateClass {}
}