Kotlin Initialize Variable Inside Function in Constructor - class

In Kotlin variables not declared as nullable or lateinit must be initialized in the constructor (or init). I am trying to do this like this:
class Foo{
var foo:myType
init{
complicatedFooInit()
}
fun complicatedFooInit(){
foo = //a whole bunch of code here
}
}
I still get the Property must be initialized or declared abstract error. You can easily reproduce this by making myType an Int and just setting it equal to 3 in the complicatedFooInit function. Obviously there are ways around this (just not making it a function, having complicatedFooInit return myType and setting foo equal to it, etc.). My question is, why is the above code invalid? Or is it valid with some tweaking?

Compiler have no idea what's going on inside complicatedFooInit() function (cause it may be too burden to investigate all execution flow of potentially dozens nested functions called from init block). He wants to see initialization directly inside init block. So you need to make complicatedFooInit() return desired value:
class Foo {
var foo: myType
init {
foo = complicatedFooInit()
}
fun complicatedFooInit(): myType {
//a whole bunch of code here
return ...
}
}
Actually, in this case property initialization on declaration site will be more concise (no need for init block at all):
var foo: String = complicatedFooInit()

Consider also that you can have multiple init blocks, so if you want to extract some part of initialization into a function, e.g.
init {
complicatedFooInit()
complicatedBarInit()
}
I would replace each function by a separate init block:
// comment about foo initialization
init {
// body of complicatedFooInit()
}
// comment about bar initialization
init {
// body of complicatedBarInit()
}
The problem is that you can't pass arguments to init blocks; but any arguments you'd pass to complicatedFooInit can only depend on the primary constructor parameters, and so can be set up in the beginning of the corresponding init block.
You also can't call the same function twice with different parameters,
init {
complicatedFooInit(true)
complicatedFooInit(false)
}
but you wouldn't want to anyway, because it would initialize foo twice; unless complicatedFooInit initializes different variables depending on its arguments, but it would make the compiler's burden mentioned in Михаил Нафталь's answer much worse!

Related

What is the difference between "lazy var funcName: () -> Void" and regular function declaration in Swift

I have recently encountered such code block when I was working on a different codebase.
I was wondering is there any significant difference (in terms of memory impact etc.) between these two declarations other than syntactic ease? I regularly use lazy stored properties but I couldn't visualize how a function can be "lazy". Can you guys also enlighten me how functions are processed (or share an article explaining this topic) by the swift compiler as well?
Thanks in advance, wish you bug free codes.
A few differences I can think of off the top of my head:
With functions, you can use parameter labels to make the call site more readable, but since you can't add parameter labels to function types, you can't do that with the lazy var declaration.
// doesn't work
lazy var say: (message: String, to person: String) -> Void = {
...
}
// works
func say(message: String, to person: String) {
...
}
You can only invoke a function type with no parameter labels at all :( say("Hello", "Sweeper") instead of say(message: "Hello", to: "Sweeper").
lazy vars are variables, so someone could just change them:
helloFunc = { /* something else */ }
you could prevent this by adding a private setter, but that still allows setting it from within the same class. With a function, its implementation can never be changed at runtime.
lazy vars cannot be generic. Functions can.
// doesn't work
lazy var someGenericThing<T>: (T) -> Void = {
...
}
// works
func someGenericThing<T>(x: T) {
...
}
You might be able to work around this by making the enclosing type generic, but that changes the semantics of the entire type. With functions, you don't need to do that at all.
If you're implementing a language, the magic you need to implement 'lazy' as a feature is to make the value provided silently be wrapped in a function (of no arguments) that is automatically evaluated the first time the property is read.
So for example if you have
var x = SomeObject() // eagerly construct an instance of SomeObject
and
lazy var x = SomeObject() // construct an instance if/when someone reads x
behind the scenes you have, for the lazy var x, either x has not yet been read, or it has been and therefore has a value. So this is like
enum Lazy<T> {
case notReadYet(() -> T) // either you have a function that makes the initial T
case read(T) // or you have a value for T
}
var thing: Lazy<SomeObject> = .notReadYet { return SomeObject() }
and with a suitable property wrapper or other language magic, wrap the calls to the getter for thing with a switch on the case, which checks if you are in the notReadYet case, and if so automatically invoke the function to produce the T and then set the property to .read(t) for the particular value of t.
If you substitute in your type: () -> Void from your example you have something like:
var thing: Lazy<() -> Void> = .notReadYet({ return { print("Hello") } })
This is all rather odd because it's a void value and not much point making it lazy, e.g. it's not expensive to compute; it doesn't help break a two-phase initialisation loop, so why do it?

Are you required to call the a super class's implementation from each and every subclass's function

e.g. you have a subclass defined which overrides a function f in its superclass. Inside the override, are you required to call the superclass's f function.
The answer to this question is not really related to Swift but it's related to all OOP languages.
The simple answer is: No, you are not required to call the superclass implementation.
Whether you should call the superclass implementation or not should be stated in the documentation. When you are not sure, you should generally always call the super implementation.
You have to consider the fact that the superclass does something inside the method and if you don't call the superclass implementation, the subclass doesn't have to work properly.
Not calling the superclass implementation means that you want to prevent the superclass implementation from happening and that usually means your whole inheritance model is flawed.
One notable exception is the situation when the superclass provides some default implementation which you want to replace inside your subclass (e.g. UIViewController.loadView). That's not a very common use case though.
There are also other obvious exceptions, for example getters. When you are overriding a getter to return a custom object, there is usually no need to call super. However, again, even getters can technically initialize some structures in the superclass and it might be needed to call super.
The answer is false, you don't need to call the superclass method you are overriding in Swift or in OOP in general. That would be a horrible limitation if you did! There are times when you should in fact not call it and perhaps the most common example is when you create a UIViewController programmatically and have to override loadView() without calling super.loadView().
The default is that you call super, unless you know you're not breaking that function.
I've created a gist. You can copy it to your own playground and play around with it. But the answer is:
I had this exact confusion of yours. You're basically asking what's the difference between extending behavior vs. overriding behavior.
Swift doesn't do a good a job of telling your their difference.
What they both share is that both need to mark the function with override, but sometimes you're doing something in addition to the superclass's implementation (extending), and sometimes you're just completely rewriting it (overriding)
Suppose we have the following class:
class Person {
var age : Int?
func incrementAge() {
guard age != nil else {
age = 1
return
}
age! += 1
}
func eat() {
print("eat popcorn")
}
}
We can just initialize it and do:
var p1 = Person()
p1.incrementAge() // works fine
Now suppose we did this:
class Boy : Person{
override func incrementAge() {
age! += 2
}
}
var b1 = Boy()
b1.incrementAge()
What do you think is going to happen?!
It will crash. Because in the super class, we're doing a nil check for age, but in our subclass we never call super
To make it work we have to call super.
class GoodBoy : Person{
override func incrementAge() {
super.incrementAge()
age! += 2
}
}
var b2 = GoodBoy()
b2.incrementAge() // works fine.
We could get away without calling super directly.
class AlternateGoodBoy : Person{
override func incrementAge() {
guard age != nil else {
age = 1
return
}
age! += 2
}
}
var b3 = AlternateGoodBoy()
b3.incrementAge() // works fine.
^^ The above works, yet the superclass's implementation is not always known to us. A real example is UIKit. We don't know what happens really when viewDidLoad is called. Hence we must call super.viewDidLoad
That being said sometimes we could just not call super and be totally fine because we know what super does or maybe just don't care and want to completely get rid of it. e.g. :
class Girl : Person{
override func eat() {
print("eat hotdog")
}
}
var g1 = Girl()
g1.eat() // doesn't crash, even though you overrode the behavior. It doesn't crash because the call to super ISN'T critical
Yet the most common case is that you call super, but also add something on top of it.
class Dad : Person {
var moneyInBank = 0
override func incrementAge() {
super.incrementAge()
addMoneyToRetirementFunds()
}
func addMoneyToRetirementFunds() {
moneyInBank += 2000
}
}
var d1 = Dad()
d1.incrementAge()
print(d1.moneyInBank) // 2000
Pro tip:
Unlike most overrides where you first call super then the rest, for a tearDown function, it’s best to call super.tearDown() at the end of the function. In general, for any 'removal' functions, you'd want to call super at the end. e.g. viewWillDisAppear/viewDidDisappear

Swift create custom initializer without parameters with custom name

I want to create init for my class that might look something like this:
initWithSomeMode { // Not compilable
self.init()
self.customSetup()
}
Of course code above will not work, I just want to show what I want to achieve.
I can only see convenience init in Swift class, but in that case I need to add parameters, but I don't need them.
So, I might achieve this with convenience init something like this:
convenience init(foo: String?) {
self.init()
self.customSetup()
}
Is there any way to create custom init without parameters?
You need to create a static method:
static func initWithSomeMode() -> YourClass {
let obj = YourClass()
obj.someCustomSetup()
return obj
}
And then you can do this:
let yourClass = YourClass.initWithSomeMode()
Also a workaround, but I tend to use this:
convenience init(withSomeMode: Void) {
self.init()
self.customSetup()
}
and then:
YourClass.init(withSomeMode: ())
it has some advantages over static method, like easier subclassing. But yes, still a workaround.
In current Swift you can only write a single no-parameter method that follows the Swift initialization process and rules: init()
To customize initialization, you must provide named input parameters: init(with: String)
There is no way to write a no-parameter "named initializer" to the left of the ( and still have it be an initialization function that follows the init rules. Something like initSpecial() won't work.
Initializers
Initializers are called to create a new instance of a particular type. In its simplest form, an initializer is like an instance method with no parameters, written using the init keyword.
Customizing Initialization
You can customize the initialization process with input parameters and optional property types, or by assigning constant properties during initialization, as described in the following sections.
https://docs.swift.org/swift-book/LanguageGuide/Initialization.html

How to get class type statically in swift

As the question may seem duplicated, I point out first that this is not asking for how to get a class type from an instance ( answer is using type(of:) ).
protocol Owner {
static func name() -> String
}
extension Owner {
static func name() -> String {
return "\(self)"
}
}
class Foo {
var ownerName: String
init(with owner: Owner.Type) {
ownerName = owner.name()
}
}
class Bar: Owner {
var foo = Foo(with: Bar.self)
}
The code above simply works, but imagine that I want to rename the class Bar to BarBar then I need to change the initialization of foo to Foo(with: BarBar.self) manually. Is there any keyword that can be used instead of ClassName.self (e.g. Bar.self BarBar.self) to get the class type? Something like Self or Class (they don't compile actually)
My guess is that your whole question is a red herring and that type(of:self) is exactly what you want to say. In that case, the problem is merely that var foo is declared as an instance property. There are special rules for when you are allowed to say self while initializing an instance property (rightly, because self is exactly what does not yet exist during initialization). However, there are ways around that, as I have explained elsewhere; you can make this a computed instance property, or a lazy instance property, which is initialized by a function to be executed later, and then you are allowed to say type(of:self).

Accessing "self" in initializing closure

In Swift 3 the dispatch_once function was removed and the migration guide suggests to use initializing closure:
let myGlobal = { … global contains initialization in a call to a closure … }()
_ = myGlobal // using myGlobal will invoke the initialization code only the first time it is used.
I'd like to access 'self' instance variables from within the initializing closure like so:
class SomeClass {
var other = SomeOtherClass()
let initialize: () = {
// self.other - this doesn't work, complains about unresolved identifier 'self'
// how to access self.other here?
} ()
func doSomething() {
// initialize will only be called once
initialize
}
}
Why is 'self' not accessible in the closure and how can make it to be?
This quoted example of the Migration Guide is misleading because it's related to a global variable.
The closure of a instance let constant is called (once) immediately when the class is initialized. That's the reason why it cannot use other variables declared on the same level.
What you can do is to initialize initialize (the variable name is not the best one ;-) ) lazily. The closure is also called only once but – as the guide describes – only the first time (when) it is used.
class SomeClass {
let other = SomeOtherClass()
lazy var initialize : () = {
let test = self.other
test.doSomething()
}()
func doSomething() {
// initialize will only be called once
_ = initialize
}
}
When an instance of the 'SomeClass' class is created, it will first create all of the variables and constants on that instance. During this time, self may not be fully initialised, because it may be halfway through setting up. Because of this, self is not available until after the initialisation step has completed.
In the example, they were talking about a global variable which has no concept of self, or a static constant on the class which also has no concept of self.
If it needs to be an instance method/variable you could:
a) make it a lazy var like
lazy var initialise : ()->Void = {
return {
// can access self here
}
}()
which will be created the first time you call it, rather than during initialisation. Of course you lose the constant that way, and you have to store the closure which is wasteful since you're only executing it once.
b) put the code inside of an init method:
init() {
// if your class doesn't have a super class, you can access self.other here.
// If it does have a super class (like NSObject) you must first call super.init() here to complete the initialisation.
// This can only be done after all other variables have been set.
}