breandan
breandan

Reputation: 2024

How to explicitly invoke an object's init block?

I have a class that looks something like the following. On line 7, I would like to invoke the init block directly, however this does not seem to be possible without using reflection.

object MyClass {
    var editor: Editor = getDefaultEditor()
        set(value) {
            field = value

            //Todo: figure out how to avoid duplicating init block
            project = editor.project!!
            document = editor.document.charsSequence.toString().toLowerCase()
            findModel = FindManager.getInstance(project).findInFileModel.clone()
            findManager = FindManager.getInstance(project)
        }

    var project: Project
    var document: String
    var findModel: FindModel
    var findManager: FindManager

    init {
        project = editor.project!!
        document = editor.document.charsSequence.toString().toLowerCase()
        findModel = FindManager.getInstance(project).findInFileModel.clone()
        findManager = FindManager.getInstance(project)
    }
}

But I need to have the init block in order to initialize the properties without instantiating, so if I replace the code inside the init block with setEditor(getDefaultEditor()), then the compiler will complain that, "Property must be initialized or be abstract". How do I avoid duplicating all the stuff inside init?

Upvotes: 1

Views: 1704

Answers (2)

Lukas Lechner
Lukas Lechner

Reputation: 8191

I do not know if it is possible to explicitly call the init block.

But I think this should do it for you:

object MyClass {

    var editor: Editor = getDefaultEditor()
        set(value) {
             field = value
             init()
        }

    lateinit var project: Project
    lateinit var document: String
    lateinit findModel: FindModel
    lateinit var findManager: FindManager

    init {
        init()
    }

    private fun init() {
        project = editor.project!!
        document = editor.document.charsSequence.toString().toLowerCase()
        findModel = FindManager.getInstance(project).findInFileModel.clone()
        findManager = FindManager.getInstance(project)
    }
}

But a better design would simply be this:

object MyClass {

    var editor: Editor = getDefaultEditor()

    fun getProject() = editor.project!!
    fun getDocument() = editor.document.charsSequence.toString().toLowerCase()
    fun getFindModel() = FindManager.getInstance(getProject()).findInFileModel.clone()
    fun getFindManager() = FindManager.getInstance(getProject())
}

Upvotes: 0

klimat
klimat

Reputation: 24991

You can use lateinit to say to the compiler "I'll initialize that property later".

lateinit var project: Project
lateinit var document: String
lateinit var findModel: FindModel
lateinit var findManager: FindManager

Then you can omit initialization in init block and do it whenever you want.

A notice from the official documentation:

The modifier can only be used on var properties declared inside the body of a class (not in the primary constructor), and only when the property does not have a custom getter or setter. The type of the property must be non-null, and it must not be a primitive type.

Accessing a lateinit property before it has been initialized throws a special exception that clearly identifies the property being accessed and the fact that it hasn't been initialized.

Upvotes: 3

Related Questions