Kotlin primary constructor calling secondary constructor

6.8k Views Asked by At

Why does this not compile?

class test
{
  constructor() {
      var a = Date().day
      this(a)
  }

  constructor(a:Int) {
  }
}

error is: Expression 'this' of type 'test' cannot be invoked as a function. The function 'invoke()' is not found.

The suggested fix is to add this:

private operator fun invoke(i: Int) {}

Why?

3

There are 3 best solutions below

3
On

First, both of these constructors are secondary constructors. A primary constructor is one which is located outside of the body of the class.

Second, as described in the documentation, the correct syntax to call another constructor is as follows:

class Test {
    constructor() : this(1) { }

    constructor(a: Int) { }
}
0
On

Couple of things are wrong here:

  • Classes should always use camel-case for their names (test -> Test)
  • You cannot call another constructor as you tried to (calling this(1) inside of the other constructors body)

I think what you actually want is a being a property and alternatively initialize it with a default value. You could do it like this

class Test(val a: Int) {
    constructor() : this(1) // notice how you can omit an empty body
}

or even better, like this:

class Test(val a: Int = 1) // again an empty body can be omitted.

Edit:

If you need to do some calculations, as asked in the comment below Yole's answer:

class Test(val day: Int) {
    // you can use any expression for initialization
    constructor(millis: Long) : this(Date(millis).day) 
}

or if things get more complicated:

class Test(var day: Int) {
    // pass something (i.e. 1) to the primary constructor and set it properly in the body
    constructor(millis: Long) : this(1) { 
        // some code
        day = // initialize day
    }
}
0
On
class test constructor(){ // primary constructor (The primary constructor is part of the class header: it goes after the class name (and optional type parameters))

    constructor(a: Int) : this() { // secondary constructor

    }
}

If you class have define primary constructor, secondary constructor needs to delegate to the primary constructor. See here.

I think primary constructor can not be called from secondary constructor.

You can think like this: secondary calls primary and primary calls secondary => endless loop => not possible

In your case, there are 2 secondary constructor, so you can do like

class test {

    constructor() : this(Date().day) // I see it quite like Java here https://stackoverflow.com/questions/1168345/why-do-this-and-super-have-to-be-the-first-statement-in-a-constructor

    constructor(a: Int) {
    }
}