How to initialize members of the class in kotlin when we are using both primary and secondary constructor?

Viewed 809

I am new to kotlin and was learning about classes recently. I don't understand why i am getting this error "property must be initialized or abstract" for _age variable. Although I have initialized it in the secondary constructor.

 class Person(firstname:String,lastname:String)
{

   var _firstname: String

   var _lastname: String    
   var _age:Int            

   init{        
       _firstname=firstname 
       _lastname=lastname                        
       println("The name of the person is $firstname ")
   } 
 constructor(firstname:String="Jack",lastname:String="Sparrow",age:Int)
 :this(firstname,lastname) {    
           _age=age
           println("The age of $_firstname $_lastname is $age")
   }

}

1 Answers

This error is telling you that there is at least one way to construct instances of your class without initializing the _age property.

The secondary constructor always delegates to the primary constructor, but not the other way around. This means, as @gidds pointed out, that if someone calls the primary constructor directly, the property _age will never get a chance to be initialized, hence your error here:

val person = Person("John", "Doe") // what would _age be here?

It's usually easier to make the primary constructor deal with all the state that you need, and provide either arguments with default values or secondary constructors if you want optional ways to construct instances without all the information.

In your case, you don't really need a secondary constructor at all here, you should just need default values for your primary constructor arguments.

Also, you can use a shorter syntax for your primary constructor, which allows you to declare its arguments and define properties of your class at the same time:

class Person(
    val firstname: String,
    val lastname: String,
    val age: Int = 25, // whichever default you want here
) {
    init {
        println("The name of the person is $firstname")
        println("The age of $firstname $lastname is $age")
    }
}

The above is quite compact, and defines the following:

  • a primary constructor with arguments firstname, lastname and age, where age is an optional argument with a default value
  • 3 read-only properties (because of val) on your class, which have the same names as the primary constructor arguments

When the constructor is called, the properties are automatically initialized with the values of the constructor argument, and then the init block is executed.

Side notes:

  • avoid var as much as possible, prefer read-only vals instead. They are easier to reason about, for humans and for the compiler, which can do better smart casts and optimizations
  • avoid the _ prefix in general, and especially in public property (this is not very standard Kotlin style)
Related