Does Kotlin Support Member Sealed Overrides? - kotlin

In Kotlin we can modify a class with the sealed modifier to denote that the class can only be extended within the same module; or from the docs:
Sealed classes and interfaces represent restricted class hierarchies that provide more control over inheritance. All subclasses of a sealed class are known at compile time. No other subclasses may appear after a module with the sealed class is compiled. For example, third-party clients can't extend your sealed class in their code. Thus, each instance of a sealed class has a type from a limited set that is known when this class is compiled.
What I want to know is, can the same or similar behaviour be applied to class members; for example, consider the following code. All of the classes and interfaces exist in the same module:
// I don't want to seal this because it should be implementable beyond this module.
interface Hashable {
val hash: Hash
}
// I don't want to seal this because it should be extensible beyond this module.
abstract class Base : Hashable {
final override val hash: Hash get() = hashOf(...)
}
open class Derived : Base {
// This doesn't work because it's final in the base class.
final override val hash: Hash get() = hashOf(...)
}
What I essentially want to express is, "I (the developer) determine how a Base should create it's hash, until I (the developer) state otherwise in a derived class. Nobody else outside of this module has the ability to alter how each extension or derivative of Base may create its hash."
Is this possible?

You can create additional property with internal visibility:
abstract class Base : Hashable {
final override val hash: Hash get() = _hash
internal open val _hash: Hash get() = hashOf(...)
}
open class Derived : Base() {
override val _hash: Hash get() = hashOf(...)
}

Related

What is the difference between open class and abstract class?

abstract class ServerMock(param: String) {
protected var someVar = params + "123"
fun justMyVar() = someVar
}
Usage example:
class BaseServer(param: String) : ServerMock(param) {
val y = someVar
}
Can this class be marked as open and not abstract?
What is the difference between open and abstract class?
abstract class cannot be instantiated and must be inherited, abstract classes are open for extending by default. open modifier on the class allows inheriting it. If the class has not open modifier it is considered final and cannot be inherited.
You can not instantiate an abstract class. You either need to subclass or create an anonymous class using object. In abstract classes you can just declare function without implementing them (forcing the subclass to imlement them) or provide a default implementation.
abstract class BaseClass {
fun foo() // subclasses must implement foo
fun bar(): String = "bar" // default implementation, subclasses can, but does not have to override bar
}
// error: can not create an instance of an abstract class
val baseClass = BaseClass()
class SubClass : BaseClass {
// must implement foo
override fun foo() {
// ...
}
// can, but does not need to override bar
}
// declaring an anonymous class (having no name) using object keyword
val baseClass: BaseClass = object : BaseClass {
// must implement foo
override fun foo() {
// ...
}
// it is optional implementing bar
override fun bar(): String {
return "somethingElse"
}
}
A class that is neither abstract nor open is considered to be final and can not be extended.
If you want to allow subclassing you should mark it open.
class AClass
// error: This type is final, so it can not be inherrited from.
class BClass : AClass
open class CClass
class DClass : CClass
So if you want to allow BaseServer to be subclassed you should mark it open. If you also want to declare functions, but force subclasses to implement them you can replace open with abstract.
Documentation
Kotlin Abstract Classes
Kotlin Inheritance (incl. open)
Imagine you have 2 classes
Class Person [parent class]
Class Coder [sub/child class]
When you want to inherit Coder from Person you have to make Person open, so it is available to inherit from.
Meanwhile you can make objects from Person itself.
When you don't need to make objects from parent class(in our case it's Person) or you don't see any meaning creating objects from it you can use abstract instead of open.
It works the same way as open does. But the main difference is that you cannot make objects from Person(parent class) anymore.

Why we should avoid using open members of base class?

While i am reading document of Kotlin, i saw that we should avoid using open properties declared at base class:
It means that, by the time of the base class constructor execution, the properties declared or overridden in the derived class are not yet initialized. If any of those properties are used in the base class initialization logic (either directly or indirectly, through another overridden open member implementation), it may lead to incorrect behavior or a runtime failure. When designing a base class, you should therefore avoid using open members in the constructors, property initializers, and init blocks.
The document said that properties in derived class are not yet initialized when base class's constructor is called. But, how can we access derived class's properties which are not initialized, from base class constructor(I assumed that the incorrect behavior or a runtime failure were caused by this situation)? Is it possible?
I don't know kotlin, but I'm assuming that open is the same as virtual in other languages. It is unsafe to call virtual members in a base class constructor because the base constructor is called before the derived constructor. If the overridden property requires that the derived class be fully initialized it can cause errors because the derived constructor has not yet been called when you are inside the base constructor. At least that is the way it works in .NET languages like C#.
Open functions in Kotlin are functions which can be overridden by a subclass. Generally, it's a good practice to limit a class's inheritance because you should provide a class with it's necessary codes to make it overridable. If your intention is not to let a class to override your base class, then you should make it final. So Kotlin make this easy by making each class and method final by default. You can find a more detailed answer in the Objects and Class chapter of the book Kotlin in Action.
The so-called fragile base class problem occurs when modifications of a base class
can cause incorrect behavior of subclasses because the changed code of the base class no
longer matches the assumptions in its subclasses. If the class doesn’t provide exact rules
for how it should be subclassed (which methods are supposed to be overridden and how),
the clients are at risk of overriding the methods in a way the author of the base class
didn’t expect. Because it’s impossible to analyze all the subclasses, the base class is
"fragile" in the sense that any change in it may lead to unexpected changes of behavior in
subclasses.
To protect against this problem, Effective Java by Joshua Bloch (Addison-Wesley,
2008), one of the best-known books on good Java programming style, recommends that
you "design and document for inheritance or else prohibit it." This means all classes and
methods that aren’t specifically intended to be overridden in subclasses need to be
explicitly marked as final .
Kotlin follows the same philosophy. Whereas Java’s classes and methods are open by
default, Kotlin’s are final by default.
I assume you are asking about this example in Kotlin documentation:
open class Base(val name: String) {
init { println("Initializing a base class") }
open val size: Int =
name.length.also { println("Initializing size in the base class: $it") }
}
class Derived(
name: String,
val lastName: String,
) : Base(name.replaceFirstChar { it.uppercase() }.also { println("Argument for the base class: $it") }) {
init { println("Initializing a derived class") }
override val size: Int =
(super.size + lastName.length).also { println("Initializing size in the derived class: $it")
}
}
Kotlin designers followed good practices learned, from other language mistakes, so they made class, properties, and functions closed by default for overriding or inheriting. why?
let's add the open modifier to the base class property and override it:
open class Base(open val name: String) {
init { println("Initializing a base class") }
open val size: Int =
name.length.also { println("Initializing size in the base class: $it") }
}
class Derived(
override val name: String,
val lastName: String,
) : Base(name.replaceFirstChar { it.uppercase() }.also { println("Argument for the base class: $it") }) {
init { println("Initializing a derived class") }
override val size: Int =
(super.size + lastName.length).also { println("Initializing size in the derived class: $it") }
}
fun main() {
println("Constructing the derived class(\"hello\", \"world\")")
Derived("hello", "world")
}
if you run this code the output will be like below:
Constructing the derived class("hello", "world")
Argument for the base class: Hello
Initializing a base class
**Exception in thread "main" java.lang.NullPointerException
at Base.<init> (File.kt:6)
at Derived.<init> (File.kt:12)
at FileKt.main (File.kt:23)**
The error is happening because this line of code
open val size: Int =
name.length.also { println("Initializing size in the base class: $it") }
Why? when we were trying to initialize the Derived class, first the superclass is initialized first, so the initialization is done by evaluating the super constructor argument, then the properties and init blocks in their declaration order in the class.
when it comes to val size: Int = name.length.also{...} the initialization calls the name property which is overridden by the Derived class, the one that does NOT yet initialize.
so by avoiding marking the base properties by open, you protect the base class client from abusing the class.

Why private constructor of sealed class can be called in sub class?

Sealed class in Kotlin can have private constructor only. That means we can call the constructor only in itself:
Sealed classes are not allowed to have non-private constructors (their constructors are private by default).
// `private` and `constructor()` are redundant.
sealed class Expr private constructor()
But, when we utilize sealed class, a sub class have to inherit seald class:
// Above Kotlin 1.1
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
As you can see the code above, sealed class's private constructor is called outside of sealed class itself. When sub class is instantiated, the constructor of parent(sealed class) will be called before sub class's own constructor is called. Is it just exception to visibility modifiers?
https://kotlinlang.org/docs/reference/visibility-modifiers.html#classes-and-interfaces
For members declared inside a class: private means visible inside this class only (including all its members);
Consider the following code:
open class A private constructor(var name: String){
class B : A("B")
class C : A("C")
}
The above code compiles fine, as the constructor is called inside the class A.
If a class D tries to inherit outside A, it won't compile.
class D : A("D") // Error: Cannot access '<init>': it is private in 'A'
As mentioned on the page Sealed class in Kotlin,
A sealed class can have subclasses, but all of them must be declared in the same file as the sealed class itself. (Before Kotlin 1.1, the rules were even more strict: classes had to be nested inside the declaration of the sealed class).
It seems that kotlin relaxed the requirement of nested classes only.
So, the following code works fine in 1.1+ but would fail in earlier versions:
sealed class A(var name: String)
class B : A("B")
class C : A("C")
whereas the following code would have been required in versions before 1.1, which respects the private constructor.
sealed class A (var name: String){
class B : A("B")
class C : A("C")
}
So, allowing private constructors of sealed classes outside the class (but within the same file) can be considered an enhancement to make the code cleaner.
You can figure out what's happening by taking a look at the generated bytecode (you can do this by going to Tools -> Kotlin -> Show Kotlin Bytecode and then choosing Decompile in the pane that appears.). Decompiling it to Java shows this code for the Expr class:
public abstract class Expr {
private Expr() {
}
// $FF: synthetic method
public Expr(DefaultConstructorMarker $constructor_marker) {
this();
}
}
So there is a non-private constructor for the Expr class generated, with a special parameter. Then, as you'd expect, if you look at the decompiled bytecode of Const for example, you'll see that it calls into this constructor:
public final class Const extends Expr {
public Const(double number) {
super((DefaultConstructorMarker)null);
this.number = number;
}
// other fields and methods ...
}
You still can't subclass Expr from Kotlin, because the Kotlin compiler knows that it's a sealed class from the metadata in the file, and will respect that.
As for Java client code, there you can't access this same constructor yourself because the DefaultConstructorMarker is package-private in the kotlin.jvm.internal package that it's in, so even if you write out the import statement for it manually, the compiler won't allow it.
My guess is that the package-private visibility might only be enforced at compile time, and that's why the Kotlin compiler is able to output the bytecode corresponding to the snippet above (not completely sure though).

Kotlin: why use Abstract classes (vs. interfaces)?

I'm aware of two differences between Abstract classes and Interfaces in Kotlin:
An abstract class can have state (e.g. var...)
A class can implement multiple interfaces, but not multiple abstract classes.
Since Kotlin is a rather fresh language, I wonder why Abstract Classes were not abandoned? Interfaces seem superior tool, with a very little need for Abstract Classes.
To elaborate: Kotlin does support concrete function implementation in interfaces, e.g.:
interface Shiny {
fun shine(amount : Int) // abstract function
fun reflect(s : String) { print ("**$s**") } // concrete function
}
Can someone provide a strong practical example of the need for Abstract Classes?
The practical side of abstract classes is that you can encapsulate a part of implementation that works with the state, so that it cannot be overridden in the derived classes.
In an interface, you can only define a property without a backing field, and an implementation class must override that property (with either a backing field or custom accessors).
Given that, you cannot define logic that stores some state in an interface in a reliable way: an implementation class might override the properties in an unexpected way.
Example:
interface MyContainer {
var size: Int
fun add(item: MyItem) {
// ...
size = size + 1
}
}
Here, we provide a default implementation for add that increments size. But it might break if an implementing class is defined like this:
class MyContainerImpl : MyContainer {
override val size: Int
get() = 0
set(value) { println("Just ignoring the $value") }
}
On contrary, abstract classes support this use case and thus allow you to provide some guarantees and contract for all their implementations: they can define some state and its transitions that will stay the same in a derived class.
Apart from that, abstract classes can have non-public API (internal, protected) and final members, whereas interfaces cannot (they can only have private members, which can be used in the default implementations), and all their default implementations can be overridden in the classes.
Abstract classes exist essentially for a hierarchy of classes. For example, if the abstract parent class had a concrete function that was also defined in the child class which extends the parent class, then in certain cases it would be necessary to call the parent's function. When you use an interface it is impossible to do so due to the entirely abstract nature of the class.

Why do we use "companion object" as a kind of replacement for Java static fields in Kotlin?

What is the intended meaning of "companion object"? So far I have been using it just to replace Java's static when I need it.
I am confused with:
Why is it called "companion"?
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
To instantly create a singleton instance that is scoped to a class, I often write
:
companion object {
val singleton by lazy { ... }
}
which seems like an unidiomatic way of doing it. What's the better way?
What is the intended meaning of "companion object"? Why is it called "companion"?
First, Kotlin doesn't use the Java concept of static members because Kotlin has its own concept of objects for describing properties and functions connected with singleton state, and Java static part of a class can be elegantly expressed in terms of singleton: it's a singleton object that can be called by the class' name. Hence the naming: it's an object that comes with a class.
Its name used to be class object and default object, but then it got renamed to companion object which is more clear and is also consistent with Scala companion objects.
Apart from naming, it is more powerful than Java static members: it can extend classes and interfaces, and you can reference and pass it around just like other objects.
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
Yes, that's the idiomatic way. Or you can even group them in non-companion objects by their meaning:
class MyClass {
object IO {
fun makeSomethingWithIO() { /* ... */ }
}
object Factory {
fun createSomething() { /* ... */ }
}
}
To instantly create a singleton instance that is scoped to a class, I often write /*...*/ which seems like an unidiomatic way of doing it. What's the better way?
It depends on what you need in each particular case. Your code suits well for storing state bound to a class which is initialized upon the first call to it.
If you don't need it to be connected with a class, just use object declaration:
object Foo {
val something by lazy { ... }
}
You can also remove lazy { ... } delegation to make the property initialize on first class' usage, just like Java static initializers
You might also find useful ways of initializing singleton state.
Why is it called "companion"?
This object is a companion of the instances.
IIRC there was lengthy discussion here: upcoming-change-class-objects-rethought
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
Yes. Every "static" property/method needs to be placed inside this companion.
To instantly create a singleton instance that is scoped to a class, I often write
You do not create the singleton instance instantly. It is created when accessing singleton for the first time.
which seems like an unidiomatic way of doing it. What's the better way?
Rather go with object Singleton { } to define a singleton-class. See: Object Declarations
You do not have to create an instance of Singleton, just use it like that Singleton.doWork()
Just keep in mind that Kotlin offers other stuff to organize your code. There are now alternatives to simple static functions e.g. you could use Top-Level-Functions instead.
When the classes/objects with related functionalities belong together, they are like companions of each other. A companion means a partner or an associate, in this case.
Reasons for companionship
Cleaner top-level namespace
When some independent function is intended to be used with some specific class only, instead of defining it as a top-level function, we define it in that particular class. This prevents the pollution of top-level namespace and helps with more relevant auto-completion hints by IDE.
Packaging convenience
It's convenient to keep the classes/objects together when they are closely related to each other in terms of the functionality they offer to each other. We save the effort of keeping them in different files and tracking the association between them.
Code readability
Just by looking at the companionship, you get to know that this object provides helper functionality to the outer class and may not be used in any other contexts. Because if it was to be used with other classes, it would be a separate top level class or object or function.
Primary purpose of companion object
Problem: companion class
Let's have a look at the kinds of problems the companion objects solve. We'll take a simple real world example. Say we have a class User to represent a user in our app:
data class User(val id: String, val name: String)
And an interface for the data access object UserDao to add or remove the User from the database:
interface UserDao {
fun add(user: User)
fun remove(id: String)
}
Now since the functionalities of the User and implementation of the UserDao are logically related to each other, we may decide to group them together:
data class User(val id: String, val name: String) {
class UserAccess : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
}
Usage:
fun main() {
val john = User("34", "John")
val userAccess = User.UserAccess()
userAccess.add(john)
}
While this is a good setup, there are several problems in it:
We have an extra step of creating the UserAccess object before we can add/remove a User.
Multiple instances of the UserAccess can be created which we don't want. We just want one data access object (singleton) for User in the entire application.
There is a possibility of the UserAccess class to be used with or extended with other classes. So, it doesn't make our intent clear of exactly what we want to do.
The naming userAccess.add() or userAccess.addUser() doesn't seem very elegant. We would prefer something like User.add().
Solution: companion object
In the User class, we just replace the two words class UserAccess with the two other words companion object and it's done! All the problems mentioned above have been solved suddenly:
data class User(val id: String, val name: String) {
companion object : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
}
Usage:
fun main() {
val john = User("34", "John")
User.add(john)
}
The ability to extend interfaces and classes is one of the features that sets the companion objects apart from Java's static functionality. Also, companions are objects, we can pass them around to the functions and assign them to variables just like all the other objects in Kotlin. We can pass them to the functions that accept those interfaces and classes and take advantage of the polymorphism.
companion object for compile-time const
When the compile-time constants are closely associated with the class, they can be defined inside the companion object.
data class User(val id: String, val name: String) {
companion object {
const val DEFAULT_NAME = "Guest"
const val MIN_AGE = 16
}
}
This is the kind of grouping you have mentioned in the question. This way we prevent the top-level namespace from polluting with the unrelated constants.
companion object with lazy { }
The lazy { } construct is not necessary to get a singleton. A companion object is by default a singleton, the object is initialized only once and it is thread safe. It is initialized when its corresponding class is loaded. Use lazy { } when you want to defer the initialization of the member of the companion object or when you have multiple members that you want to be initialized only on their first use, one by one:
data class User(val id: Long, val name: String) {
companion object {
val list by lazy {
print("Fetching user list...")
listOf("John", "Jane")
}
val settings by lazy {
print("Fetching settings...")
mapOf("Dark Theme" to "On", "Auto Backup" to "On")
}
}
}
In this code, fetching the list and settings are costly operations. So, we use lazy { } construct to initialize them only when they are actually required and first called, not all at once.
Usage:
fun main() {
println(User.list) // Fetching user list...[John, Jane]
println(User.list) // [John, Jane]
println(User.settings) // Fetching settings...{Dark Theme=On, Auto Backup=On}
println(User.settings) // {Dark Theme=On, Auto Backup=On}
}
The fetching statements will be executed only on the first use.
companion object for factory functions
Companion objects are used for defining factory functions while keeping the constructor private. For example, the newInstance() factory function in the following snippet creates a user by generating the id automatically:
class User private constructor(val id: Long, val name: String) {
companion object {
private var currentId = 0L;
fun newInstance(name: String) = User(currentId++, name)
}
}
Usage:
val john = User.newInstance("John")
Notice how the constructor is kept private but the companion object has access to the constructor. This is useful when you want to provide multiple ways to create an object where the object construction process is complex.
In the code above, consistency of the next id generation is guaranteed because a companion object is a singleton, only one object will keep track of the id, there won't be any duplicate ids.
Also notice that companion objects can have properties (currentId in this case) to represent state.
companion object extension
Companion objects cannot be inherited but we can use extension functions to enhance their functionality:
fun User.Companion.isLoggedIn(id: String): Boolean { }
The default class name of the companion object is Companion, if you don't specify it.
Usage:
if (User.isLoggedIn("34")) { allowContent() }
This is useful for extending the functionality of the companion objects of third party library classes. Another advantage over Java's static members.
When to avoid companion object
Somewhat related members
When the functions/properties are not closely related but only somewhat related to a class, it is recommended that you use top-level functions/properties instead of companion object. And preferably define those functions before the class declaration in the same file as that of class:
fun getAllUsers() { }
fun getProfileFor(userId: String) { }
data class User(val id: String, val name: String)
Maintain single responsibility principle
When the functionality of the object is complicated or when the classes are big, you may want to separate them into individual classes. For example, You may need a separate class to represent a User and another class UserDao for database operations. A separate UserCredentials class for functions related to login. When you have a huge list of constants that are used in different places, you may want to group them in another separate class or file UserConstants. A different class UserSettings to represent settings. Yet another class UserFactory to create different instances of the User and so on.
That's it! Hope that helps make your code more idiomatic to Kotlin.
Why is it called "companion"?
An object declaration inside a class can be marked with the companion keyword:
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
Members of the companion object can be called by using simply the class name as the qualifier:
val instance = MyClass.create()
If you only use 'object' without 'companion', you have to do like this:
val instance = MyClass.Factory.create()
In my understanding, 'companion' means this object is companion with the outter class.
We can say that companion is same as "Static Block" like Java, But in case of Kotlin there is no Static Block concept, than companion comes into the frame.
How to define a companion block:
class Example {
companion object {
fun display(){
//place your code
}
}
}
Calling method of companion block, direct with class name
Example.Companion.display