Kotlin: 'This type has a constructor and thus must be initialized here', but no constructor is declared - oop

Recently started with Kotlin
According to Kotlin docs, there can be one primary constructor and one or more secondary constructor.
I don't understand why I see this error
Since class test has no primary constructor.
This works fine:
open class test {
}
class test2 : test() {
}
And here is another difficulty I have faced, when I define a secondary constructor the IDE shows another error saying
Supertype initialization is impossible without primary constructor
But in the previous working example, I did initialize it, yet it worked fine. What did I get wrong?

You get this error because, even if you don't define a primary or a secondary constructor in a base class, there is still a default no-argument constructor generated for that class. The constructor of a derived class should always call some of the super constructors, and in your case there is only the default one (this is the constructor that you can call like test() to create an object of the class). The compiler and IDE force you to do that.
The super constructor rules complicate the matter to some degree.
If you define a secondary constructor in the derived class without defining the primary constructor (no parentheses near the class declaration), then the secondary constructor itself should call the super constructor, and no super constructor arguments should be specified in the class declaration:
class test2 : test { // no arguments for `test` here
constructor(a: Int) : super() { /* ... */ }
}
Another option is define the primary constructor and call it from the secondary one:
class test2() : test() {
constructor(a: Int) : this() { /* ... */ }
}

Related

Kotlin Inheritance for Multiple Constructor Supertype

I'm trying to inherit the JFrame class. It says "This type has a constructor, and thus must be initialized here" so I can't write:
class MainFrame : JFrame
but:
class MainFrame() : JFrame()
Since I'm forced to declare a primary constructor I can't do this:
constructor(title: String) : super(title)
And I have to do this:
constructor(title: String) : this(title)
So I have to declare the primary constructor this way:
class MainFrame(title: String) : JFrame(title)
The problem is that this way every secondary constructor needs to call the primary constructor and then the supertype constructor of choice. If I have multiple supertype constructors I'm forced to delegate the process to that single supertype constructor that can be inconvenient if the supertype class has many constructors for many purposes.
There is some way to make a class with multiple constructors that call different supertype constructors?
Edit:
I can't remove the supertype constructor like this:
class MainFrame : JFrame
If I do I get this error:
This type has a constructor, and thus must be initialized here
Solution:
A constructor was missing but it can be a secondary constructor, so the error:
This type has a constructor, and thus must be initialized here
Can be solved by adding only a secondary constructor.
It is not necessary to use a primary constructor in your class definition. You can simply omit it, and then all your "secondary" constructors do not have to call a primary constructor, and can call the relevant super constructor instead.
class MainFrame: JFrame {
constructor() : super() {
}
constructor(title: String) : super(title) {
}
}
JFrame, does however follow the pattern of having an unofficial primary constructor in Java, so you could call through to this as your primary constructor and use the same defaults it uses:
class MainFrame(title: String = "", gc: GraphicsConfiguration? = null): JFrame(title, gc) {
}

What's an example of using an overridden property in the Base Class initialization (either directly or indirectly)?

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.
I was studying Inheritence from Kotlin docs, and I got stuck here. There was another post which asked a question about this, but the answers were just what the docs said in a different way.
To be clear, I understood the data flow between constructors and inheritence. What I couldn't understand was how we can use an overridden property in a base class initialization. It says
It could happen directly or indirectly
  What does this actually mean? How can the base class can somehow access to the overridden property in the derived class?
Also, it said
You should therefore avoid using open members in the constructors,
property initializers and init blocks.
 So how can we properly use open properties?
EDIT FOR THE COMMENT:
fun main ()
{
val d = Derived("Test2")
}
open class Base()
{
open val something:String = "Test1"
init
{
println(something) //prints null
}
}
class Derived(override val something: String): Base()
What does this actually mean? How can the base class can somehow access to the overridden property in the derived class?
This is one direct way:
abstract class Base {
abstract val something: String
init {
println(something)
}
}
class Child(override val something: String): Base()
fun main() {
Child("Test") // prints null! because the property is not initialized yet
}
This prints null, which is pretty bad for a non-nullable String property.
You should therefore avoid using open members in the constructors, property initializers and init blocks.
So how can we properly use open properties?
You can use these properties in regular methods on the base class (or in custom property getters):
abstract class Base {
abstract val something: String
fun printSomething() {
println(something)
}
}
class Child(override val something: String): Base()
fun main() {
Child("Test").printSomething() // correctly prints "Test"
}
EDIT: Here are some clarifications regarding the follow-up questions in the comments.
I couldn't quite get why the code in the init block went for the parameter in the child class constructor
I think you might be confused by Kotlin's compact syntax for the primary constructors in general, which probably makes the debugger's flow hard to understand. In the Child declaration, we actually declare many things:
the argument something passed to the Child's primary constructor
the property something on the Child class, which overrides the parent's one
the call to the parent constructor (Base())
When Child() is called, it immediately calls the Base() no-arg constructor, which runs the init block.
We didn't even delegate the base constructor with a parameter or anything, but it still went for the parameter who did the overriding
You might be mixing declarations and runtime here. Although we declare things in the Base class and in the Child class, there is only 1 instance at runtime (an instance of Child) in this example code.
So, in fact, there is only 1 property called something here (only one place in memory). If the init block accesses this property, it can only be the property of the child instance. We don't need to pass anything to the Base constructor because the init block is effectively executed with the data/fields of the Child instance.
Maybe you would be less confused if you saw the Java equivalent of this. It's obvious if you think of the abstract something as a declaration of a getter getSomething(). The child class overrides this getSomething() method and declares a private something field, the getter returns the current value of the field something. But that field is only initialized after the constructor of the parent (and the init block) finished executing.

What is the difference between init block and constructor in kotlin?

I have started learning Kotlin. I would like to know the difference between init block and constructor.
What is the difference between this and how we can use this to improve?
class Person constructor(var name: String, var age: Int) {
var profession: String = "test"
init {
println("Test")
}
}
The init block will execute immediately after the primary constructor. Initializer blocks effectively become part of the primary constructor.
The constructor is the secondary constructor. Delegation to the primary constructor happens as the first statement of a secondary constructor, so the code in all initializer blocks is executed before the secondary constructor body.
Example
class Sample(private var s : String) {
init {
s += "B"
}
constructor(t: String, u: String) : this(t) {
this.s += u
}
}
Think you initialized the Sample class with
Sample("T","U")
You will get a string response at variable s as "TBU".
Value "T" is assigned to s from the primary constructor of Sample class.
Then immediately the init block starts to execute; it will add "B" to the s variable.
Next it is the secondary constructor turn; now "U" is added to the s variable to become "TBU".
Since,
The primary constructor cannot contain any code.
https://kotlinlang.org/docs/reference/classes.html
the init{..} blocks allow adding code to the primary constructor.
A class in Kotlin class a primary constructor (the one after a class name) which does not contain code, it is only able to initialize properties (e.g. class X(var prop: String)).
The init{..} block in the place, where you can put more code that will run after properties are initialized:
initializer blocks are executed in the same order as they appear in the class body, interleaved with the property initializers
More about that is in https://kotlinlang.org/docs/reference/classes.html#constructors
Here is an example:
class X(var b: String) {
val a = print("a")
init {
print("b")
}
constructor() : this("aaa") {
print("c")
}
}
X()
When called it prints abc. Thus the init{..} in invoked after primary constructor but before a secondary one.
As stated in the Kotlin docs:
The primary constructor cannot contain any code. Initialization code can be placed in initializer blocks, which are prefixed with the init keyword.
During an instance initialization, the initializer blocks are executed in the same order as they appear in the class body, interleaved with the property initializers: ...
https://kotlinlang.org/docs/classes.html#constructors

In which case I have to set super() when I create a constructor?

I don't understand when I create a constructor, sometimes I have to write this
constructor(...):super(){}
Do you have an example to understand?
Consider the class Bar:
open class Foo(val i: Int)
class Bar: Foo {
constructor(i: Int): super(i)
}
Since it has no primary constructor the secondary constructor needs to invoke the constructor of the class it is derived from (which is Foo).
If the class has no primary constructor, then each secondary
constructor has to initialize the base type using the super keyword,
or to delegate to another constructor which does that. (Source)
In this particular case using a primary constructor instead would be the better way though:
class Bar(i: Int): Foo(i)
If the derived class has a primary constructor, the base class can
(and must) be initialized right there, using the parameters of the
primary constructor. (Source)

Kotlin Init Block in Super class firing with null properties when inheriting from it

open class Super {
open var name : String = "Name1"
init {
println("INIT block fired with : $name")
name = name.toUpperCase()
println(name)
}
}
class SubClass(newName : String) : Super() {
override var name : String = "Mr. $newName"
}
fun main(args: Array<String>) {
var obj = SubClass("John")
println(obj.name)
}
The above Kotlin code results in the following TypeCastException :
INIT block fired with : null
Exception in thread "main" kotlin.TypeCastException: null cannot be cast to non-null type java.lang.String
at Super.<init>(index.kt:7)
at SubClass.<init>(index.kt:13)
at IndexKt.main(index.kt:21)
As my understanding goes while inheriting from a class in Kotlin, first the primary constructors and init blocks and secondary constructors of super classes are called with passed parameters. After which the subclass can override such properties with its own version.
Then why does the above code results in the exception as described ... What am I doing wrong ... Why does the init block in super class is fired with null ...??? At first my speculation was that the init block might get fired before the actual property initialization as it is executed as a part of primary constructor but initializing the name property in the primary constructor as below gives the same error and the IDE would have warned me if so.
open class Super(open var name : String = "Name1") {
init {
println("INIT block fired with : $name")
name = name.toUpperCase()
println(name)
}
}
class SubClass(newName : String) : Super() {
override var name : String = "Mr. $newName"
}
fun main(args: Array<String>) {
var obj = SubClass("John")
println(obj.name)
}
Console :
INIT block fired with : null
Exception in thread "main" kotlin.TypeCastException: null cannot be cast to non-null type java.lang.String
at Super.<init>(index.kt:5)
at Super.<init>(index.kt:1)
at SubClass.<init>(index.kt:11)
at IndexKt.main(index.kt:19)
Am I doing something wrong here or is this a language bug...??? What can I do to avoid the error and to make the init blocks fire with the actual passed value and not null ... ??? Elaborate what is happening behind the scene. At this time I have several situations with classes like this in my actual codebase where I want to inherit from another classes, I want to maintain property names as they are...
Essentially, because you tell Kotlin that your subclass is going to be defining name now, it is not defined when the init block in Super is executed. You are deferring definition of that until the SubClass is initialized.
This behavior is documented on the Kotlin website under "Derived class initialization order":
During construction of a new instance of a derived class, the base class initialization is done as the first step (preceded only by evaluation of the arguments for the base class constructor) and thus happens before the initialization logic of the derived class is run.
...
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. Designing a base class, you should therefore avoid using open members in the constructors, property initializers, and init blocks. [emphasis mine]
FWIW, this is similar to the reason that some Java code analysis tools will complain if you refer to non-final methods in a constructor. The way around this in Kotlin is to not refer to open properties in your init blocks in the superclass.
Have the same trouble, a disgusting issue with kotlin, when subclass constructor is ignored or initialized after super class calls internal method, this is not a safe thing, if not worst i found in kotlin.