defining classes: constructors and init
python vs kotlin Syntax
# syntax is: class (): def __init__(self, ): # put init code here #now example 1 class Fred: def __init__(self, var1, var2): self.var1 = var1 self.var2 = var3 self.container = [] #and example 2 class Fred(BaseClass): def __init__(self, var1, var2): super().__init__(var1) self.var1 = var1 self.var2 = var3 self.container = [] # rest of init here
Hopefully the above python code is self explanatory. Example 2 adds a base class. I do not deal with multiple inheritance at this time, and will devote a specific page at some future time as for python it gets complex, and for kotlin it requires additional concepts. Now here is the kotlin ‘imitate python’ equivalent to example 1.
//syntax is: // class (): // // example 1a:bad version- to be python like - not best kotlin class Fred{ val var1: Int val var2: String val container: MutableList constructor(var1: Int, var2:String){ this.var1 = var1 this.var2 = var2 this.container = mutableListOf() } } // example 1b: still bad version- to be python like again- not best kotlin // move 'constructor' to class definition, now contructor body is 'init' class Fred constructor(var1: Int, var2:String){ val var1: Int val var2: String val container: MutableList init{ this.var1 = var1 this.var2 = var2 this.container = mutableListOf() } } // example 1c:better - 'constructor' keyword omitted and defines variables // in the primary constructor class Fred(val var1: Int, val var2: String){ val container: MutableList init{ container = mutableListOf() } }
First the ‘not the best kotlin way’ examples. Is constructor or init the best equivalent python init? The first example keeps the class definition more similar to python, and uses a constructor to perform the role of the python init. In kotlin, a class can have multiple different constructors to enable constructing an object from different types. So there could be another constructor accepting String in place of Int for the parameters.
But where the python code simply assigns to self.var1 without first declaring var1, in kotlin all variables must be declared, so example aside from the declarations of the three instance variables (var1, var2 and container) and constructor in place of init, 1a above looks almost directly like the python version. However, in this form, there is more code than the python version.
Version 1b above moves the constructor(var1: Int, var2:String to the class declaration. Doing this makes this the default constructor for the class, but the body of the constructor method cannot be on this line declaring the class so the body of the constructor is now called init, and the class declaration reads: class Fred constructor(var1: Int, var2:String).
init is the special reserved word to identify the block of code which is the body of the default constructor.
So example 1b is very similar to example 1a, but introduces the concept of a default constructor and the init block.
Example 1c introduces some improvement. A common pattern is that values to the constructor (init) as saved as instance variables. Simply adding var or val in the constructor means the parameter is the declaration, plus this result in the constructor automatically saving the values passed in. So we lose 4 lines of code as unnecessary (two declarations, plus 2 assignments). We can also omit the word ‘constructor’ for the primary constructor except for some rare special cases. So now the code is almost as brief as the python code. But there are still optimisations to come.
// example 1d:best class Fred(val var1: Int, val var2: String){ val container = mutableListOf() } // example 2 class Fred(val var1: Int, val var2: String):BaseClass(Var1){ val container = mutableListOf() }
So for example 1d, the code is now more concise than python, despite the declaration of variables. Yes, container does now look like a python class variable, but this is how instance variables are in kotlin. So the code is brief with types, and perhaps more so than the code without types. This is because the remaining code in the kotlin constructor prior to this step, initialisation of container, can happen at the declaration of container. So no Normally, all code needed in a constructor is setting initial values, so normally no init block is needed as initial values at the definition, either automatically in the case of default constructor parameters, or at the definition in the main block of other instance variables.
Example 2 covers a class with a base class, just for completeness, to have the syntax covered.