android/kotlin-guides

Guidelines for constructors

Opened this issue · 3 comments

I was wondering if there were currently any thoughts on constructors and guidelines around those, or if these are more of a personal preference / per basis thing?

For example, using the primary constructor where only a few param passed in is usually quite readable, but there may be some cases where there are multiple classes passed in which can cause things to get a little hard to read within a primary constructor. The constructors here are probably a bit of an exageration but are just for example case.

class ExampleClass @Inject constructor(private val dogRepository: DogRepository,
private val catRepository: CatRepository, private val fishRepository: FishRepository,
private val rabbitRepository: BirdRepository, private val birdRepository: BirdRepository) 
: SomeClass { }

compared to:

class ExampleClass : SomeClass {

    private val dogRepository: DogRepository
    private val dogRepository: DogRepository
    private val catRepository: CatRepository
    private val fishRepository: FishRepository
    private val rabbitRepository: BirdRepository
    private val birdRepository: BirdRepository

    @Inject constructor(dogRepository: DogRepository, catRepository: CatRepository, 
        fishRepository: FishRepository, rabbitRepository: BirdRepository, birdRepository) : 
        BirdRepository) {

        //assign fields

    }

}

For data classes and objects this is usually a lot more readable, but for other classes it can become harder to read.

This could be down to a lower level problem of class design and structure, but it would be good to hear if anyone is already enforcing some form of rule as I guess I'm looking for some kind of consistency 🙂 Maybe you're enforcing secondary constructors for certain classes or limiting constructors to a certain number of parameters - or you're not doing anything and just going with your gut!

Formatting suggested by JetBrains makes sense here - each parameter in new line, as well as each supertype:

class Person(
    id: Int, 
    name: String,
    surname: String
) : Human(id, name),
    KotlinMaker {
    // ...
}

Your example:

class ExampleClass @Inject constructor(
        private val dogRepository: DogRepository,
        private val catRepository: CatRepository,
        private val fishRepository: FishRepository,
        private val rabbitRepository: BirdRepository,
        private val birdRepository: BirdRepository
) : SomeClass {}

Awesome, thanks! I must have missed that. Would that be worth being added in these guidelines? Or is it enough being in the JetBrain ones alone

I guess as well I'm just curious as to what makes developers choose between one or the other, if anyone is enforcing primary constructors or if it just a personal preference thing

These technically fall under function wrapping rules, but we can clarify that it's for constructors as well as provide examples.