Why won't code that initializes a variable interface property in init block compile? - properties

interface A {
var a: Int
}
class AJunior : A {
override var a: Int
init {
a = 3
}
}
It won't compile because
Property must be initialized or be abstract
But it is initialized. I know I can write:
override var a: Int = 3
But why won't the first example compile? My guess would be that it is a bug or an intentional limitation to simplify compiler implementation, but I'm not sure.

I reported this as a bug, but turns out this behavior is by design because:
you could have code in the init block that could observe the property in its uninitialized state

Related

When does init block of object get called?

I tried to know when the init block of object gets called in Kotlin using the below code, but I don't get any result in the console:
fun main(args: Array<String>) {
TestObj
TestObj
}
object TestObj {
var count = 0
init {
fun howManyTimes() {
println(++count)
}
}
}
Dimitri's answer is correct for your problem, however the correct answer for your specific question is:
if it is a class instantiation, the init is executed before the constructor is called.
if it is an object, according to Kotlin documentation, it will be called whenever the (singleton) object is called first time, as static objects are lazy initialized.
You are not getting any output in console, because you are declaring function inside the init block, and not calling it.
Change TestObj code to:
object TestObj {
var count = 0
init {
howManyTimes()
}
fun howManyTimes() {
println(++count)
}
}
Above answer gives a clear explanation as to why you are not getting expected output, I would try to answer your question
When does init block of object get called?
From kotlin in action
The init keyword introduces an initializer block. Such blocks contain
initialization code that’s executed when the class is created, and are
intended to be used together with primary constructors. Because the
primary constructor has a constrained syntax, it can’t contain the
initialization code; that’s why you have initializer blocks. If you
want to, you can declare several initializer blocks in one class.

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.

How to write a package-level static initializer in Kotlin?

A previous question shows how to put a static initializer inside a class using its companion object. I'm trying to find a way to add a static initializer at the package level, but it seems packages have no companion object.
// compiler error: Modifier 'companion' is not applicable inside 'file'
companion object { init { println("Loaded!") } }
fun main(args: Array<String>) { println("run!") }
I've tried other variations that might've made sense (init on its own, static), and I know as a workaround I can use a throwaway val as in
val static_init = {
println("ugly workaround")
}()
but is there a clean, official way to achieve the same result?
Edit: As #mfulton26's answer mentions, there is no such thing as a package-level function really in the JVM. Behind the scenes, the kotlin compiler is wrapping any free functions, including main in a class. I'm trying to add a static initializer to that class -- the class being generated by kotlin for the free functions declared in the file.
Currently there is no way to add code to the static constructor generated for Kotlin file classes, only top-level property initializers are getting there. This sounds like a feature request, so now there is an issue to track this: KT-13486 Package-level 'init' blocks
Another workaround is to place initialization in top-level private/internal object and reference that object in those functions that depend on the effect of that initialization. Objects are initialized lazily, when they are referenced first time.
fun dependsOnState(arg: Int) = State.run {
arg + value
}
private object State {
val value: Int
init {
value = 42
println("State was initialized")
}
}
As you mentioned, you need a property with something that would run on initialisation:
val x = run {
println("The package class has loaded")
}
I got around it by using a Backing Property on the top-level, under the Kotlin file. Kotlin Docs: Backing Properties
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
// .... some other initialising code here
}
return _table ?: throw AssertionError("Set to null by another thread")
}

How do I initialize a final field in Kotlin?

Let's say I declared a final field with private final String s (Java) or val s (Kotlin). During initialization I want to initialize the field with the result of a call to a remote service. In Java I would be able to initialize it in the constructor (e.g. s = RemoteService.result()), but in Kotlin I can't figure out how to do that because as far as I can tell the field has to be initialized in the same line it's declared. What's the solution here?
You can set val value in init block:
class MyClass {
val s: String
init {
s = "value"
}
}
You can also initialize the value with by lazy the value will be initialized the first time it is referred. An example
val s by lazy { RemoteService.result() }
kotlin will guess the type of s from the return type of the expression.
You can use run:
class MyClazz {
val prop = run {
// do stuff
// do stuff again
123 // return expression
}
}
From the docs (emphasis is mine):
Besides calling run on a receiver object, you can use it as a non-extension function. Non-extension run lets you execute a block of several statements where an expression is required.
It has been possible to do it simply like this since the very first official stable release of Kotlin:
class MyClass {
val s = RemoteService.result()
}

Error in Swift class: Property not initialized at super.init call

I have two classes, Shape and Square
class Shape {
var numberOfSides = 0
var name: String
init(name:String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
class Square: Shape {
var sideLength: Double
init(sideLength:Double, name:String) {
super.init(name:name) // Error here
self.sideLength = sideLength
numberOfSides = 4
}
func area () -> Double {
return sideLength * sideLength
}
}
With the implementation above I get the error:
property 'self.sideLength' not initialized at super.init call
super.init(name:name)
Why do I have to set self.sideLength before calling super.init?
Quote from The Swift Programming Language, which answers your question:
“Swift’s compiler performs four helpful safety-checks to make sure
that two-phase initialization is completed without error:”
Safety check 1 “A designated initializer must ensure that all of the
“properties introduced by its class are initialized before it
delegates up to a superclass initializer.”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
https://itunes.apple.com/us/book/swift-programming-language/id881256329?mt=11
Swift has a very clear, specific sequence of operations that are done in initializers. Let's start with some basic examples and work our way up to a general case.
Let's take an object A. We'll define it as follows.
class A {
var x: Int
init(x: Int) {
self.x = x
}
}
Notice that A does not have a superclass, so it cannot call a super.init() function as it does not exist.
OK, so now let's subclass A with a new class named B.
class B: A {
var y: Int
init(x: Int, y: Int) {
self.y = y
super.init(x: x)
}
}
This is a departure from Objective-C where [super init] would typically be called first before anything else. Not so in Swift. You are responsible for ensuring that your instance variables are in a consistent state before you do anything else, including calling methods (which includes your superclass' initializer).
From the docs
Safety check 1
A designated initializer must ensure that all of the properties
introduced by its class are initialized before it delegates up to a
superclass initializer.
Why do we need a safety check like this?
To answer this lets go though the initialization process in swift.
Two-Phase Initialization
Class initialization in Swift is a two-phase process. In the first
phase, each stored property is assigned an initial value by the class
that introduced it. Once the initial state for every stored property
has been determined, the second phase begins, and each class is given
the opportunity to customize its stored properties further before the
new instance is considered ready for use.
The use of a two-phase initialization process makes initialization
safe, while still giving complete flexibility to each class in a class
hierarchy. Two-phase initialization prevents property values from
being accessed before they are initialized, and prevents property
values from being set to a different value by another initializer
unexpectedly.
So, to make sure the two step initialization process is done as defined above, there are four safety checks, one of them is,
Safety check 1
A designated initializer must ensure that all of the properties
introduced by its class are initialized before it delegates up to a
superclass initializer.
Now, the two phase initialization never talks about order, but this safety check, introduces super.init to be ordered, after the initialization of all the properties.
Safety check 1 might seem irrelevant as,
Two-phase initialization prevents property values from being accessed before they are initialized can be satisfied, without this safety check 1.
Like in this sample
class Shape {
var name: String
var sides : Int
init(sides:Int, named: String) {
self.sides = sides
self.name = named
}
}
class Triangle: Shape {
var hypotenuse: Int
init(hypotenuse:Int) {
super.init(sides: 3, named: "Triangle")
self.hypotenuse = hypotenuse
}
}
Triangle.init has initialized, every property before being used. So Safety check 1 seems irrelevant,
But then there could be another scenario, a little bit complex,
class Shape {
var name: String
var sides : Int
init(sides:Int, named: String) {
self.sides = sides
self.name = named
printShapeDescription()
}
func printShapeDescription() {
print("Shape Name :\(self.name)")
print("Sides :\(self.sides)")
}
}
class Triangle: Shape {
var hypotenuse: Int
init(hypotenuse:Int) {
self.hypotenuse = hypotenuse
super.init(sides: 3, named: "Triangle")
}
override func printShapeDescription() {
super.printShapeDescription()
print("Hypotenuse :\(self.hypotenuse)")
}
}
let triangle = Triangle(hypotenuse: 12)
Output :
Shape Name :Triangle
Sides :3
Hypotenuse :12
Here if we had called the super.init before setting the hypotenuse, the super.init call would then have called the printShapeDescription() and since that has been overridden it would first fallback to Triangle class implementation of printShapeDescription(). The printShapeDescription() of Triangle class access the hypotenuse a non optional property that still has not been initialised. And this is not allowed as Two-phase initialization prevents property values from being accessed before they are initialized
So make sure the Two phase initialization is done as defined, there needs to be a specific order of calling super.init, and that is, after initializing all the properties introduced by self class, thus we need a Safety check 1
The "super.init()" should be called after you initialize all your instance variables.
In Apple's "Intermediate Swift" video (you can find it in Apple Developer video resource page https://developer.apple.com/videos/wwdc/2014/), at about 28:40, it is explicit said that all initializers in super class must be called AFTER you initialize your instance variables.
In Objective-C, it was the reverse. In Swift, since all properties need to be initialized before it's used, we need to initialize properties first. This is meant to prevent a call to overrided function from super class's "init()" method, without initializing properties first.
So the implementation of "Square" should be:
class Square: Shape {
var sideLength: Double
init(sideLength:Double, name:String) {
self.sideLength = sideLength
numberOfSides = 4
super.init(name:name) // Correct position for "super.init()"
}
func area () -> Double {
return sideLength * sideLength
}
}
Sorry for ugly formatting.
Just put a question character after declaration and everything will be ok.
A question tells the compiler that the value is optional.
class Square: Shape {
var sideLength: Double? // <=== like this ..
init(sideLength:Double, name:String) {
super.init(name:name) // Error here
self.sideLength = sideLength
numberOfSides = 4
}
func area () -> Double {
return sideLength * sideLength
}
}
Edit1:
There is a better way to skip this error. According to jmaschad's comment there is no reason to use optional in your case cause optionals are not comfortable in use and You always have to check if optional is not nil before accessing it. So all you have to do is to initialize member after declaration:
class Square: Shape {
var sideLength: Double=Double()
init(sideLength:Double, name:String) {
super.init(name:name)
self.sideLength = sideLength
numberOfSides = 4
}
func area () -> Double {
return sideLength * sideLength
}
}
Edit2:
After two minuses got on this answer I found even better way. If you want class member to be initialized in your constructor you must assign initial value to it inside contructor and before super.init() call. Like this:
class Square: Shape {
var sideLength: Double
init(sideLength:Double, name:String) {
self.sideLength = sideLength // <= before super.init call..
super.init(name:name)
numberOfSides = 4
}
func area () -> Double {
return sideLength * sideLength
}
}
Good luck in learning Swift.
swift enforces you to initialise every member var before it is ever/might ever be used. Since it can't be sure what happens when it is supers turn, it errors out: better safe than sorry
Edward,
You can modify the code in your example like this:
var playerShip:PlayerShip!
var deltaPoint = CGPointZero
init(size: CGSize)
{
super.init(size: size)
playerLayerNode.addChild(playerShip)
}
This is using an implicitly unwrapped optional.
In documentation we can read:
"As with optionals, if you don’t provide an initial value when you
declare an implicitly unwrapped optional variable or property, it’s
value automatically defaults to nil."
Swift will not allow you to initialise super class with out initialising the properties, reverse of Obj C. So you have to initialise all properties before calling "super.init".
Please go to http://blog.scottlogic.com/2014/11/20/swift-initialisation.html.
It gives a nice explanation to your problem.
Add nil to the end of the declaration.
// Must be nil or swift complains
var someProtocol:SomeProtocol? = nil
// Init the view
override init(frame: CGRect)
super.init(frame: frame)
...
This worked for my case, but may not work for yours
its should be this:
init(sideLength:Double, name:String) {
self.sideLength = sideLength
super.init(name:name)
numberOfSides = 4
}
look at this link:
https://swiftgg.gitbook.io/swift/swift-jiao-cheng/14_initialization#two-phase-initialization
You are just initing in the wrong order.
class Shape2 {
var numberOfSides = 0
var name: String
init(name:String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
class Square2: Shape2 {
var sideLength: Double
init(sideLength:Double, name:String) {
self.sideLength = sideLength
super.init(name:name) // It should be behind "self.sideLength = sideLength"
numberOfSides = 4
}
func area () -> Double {
return sideLength * sideLength
}
}
#Janos if you make the property optional, you don't have to initialise it in init. –
This worked for me.