Does variable initialization out of `init{}` occur...
# announcements
a
Does variable initialization out of
init{}
occur after init and if so, is it a good practice if order matters to include it in
init{}
? i.e.,
Copy code
class Logger(val logFile: Path)
{

    val writer = Files.newBufferedWriter(logFile)
    
    init {
        if(!Files.exists(logFile))
        {
            Files.createFile(logFile)
        }
    }
}
d
They occur in order, in your case
writer
would be initialized before the
init
block. You can have multiple
init
blocks as well.
a
oh, sweet
a
The
init
block is a sore spot for kotlin. One should avid using it if possible and not place something sensitive there.
d
@altavir Why?
a
It is possible to catch java npe with wrong order.
s
You can test this for yourself by putting an init block before the
writer
declaration and attempting to use it there - you should get an error to the effect of
Variable 'writer' must be initialized
a
basically init block could call a function which references the value that is not initialized yet.
d
So can a constructor.
a
Constructor can't see functions from the same class
There are also problems with error catching and inherited classes order of init block execution.
a
so iyo
init{}
blocks are bad like Java blocks are bad?
@altavir and instead just use a
constructor
?
a
yep. exactly. The problem is it also breaks kotlin type system (nullability).
In most cases constructor + factory methods are better solution. Init is good for parameter checking.
a
aww no `val`s then 😕
s
I mean. I don’t think this precludes
val
usage. Maybe a factory method and a modified constructor would be the best way to go
a
You can do it the same way you do in java, though kotlin way is to provide everything needed as class parameters and move all initialization logic out of the class. Believe me it is much more clear that way. I've migrated my code to kotlin without knowing it, but after some time I found that I moved all init loigic to factory methods.
a
you could also remove the code from the
init
by use of lazy:
Copy code
class Logger(val logFile: Path) {

    val writer by lazy {
        if (!Files.exists(logFile)) {
            Files.createFile(logFile)
        }
        Files.newBufferedWriter(logFile)
    }
}
It changes the behaviour somewhat but is better because it keeps the code that creates the file together with the usage of the new file.
also learn about the standard code style: https://kotlinlang.org/docs/reference/coding-conventions.html#formatting Let your IDE do that for you.
It may not be the style you prefer, but examples will generally follow the standard so it might be easier for you to not have to read multiple styles.