Search code examples
kotlindslkotlin-dsl

Kotlin DSL automatically add/generate to MutableList


I've been struggling making DSL to work like this. I'd like to add items inside the lambda to the mutableList inside the persons. Can anybody help with this?

persons {
    Person("name")
    Person("name second")
}

the expected result after the lambda executed, all those item will be put inside the mutableList like this:

mutableListOf(Person("name"), Person("name second"))

Solution

  • Assuming that Person is a:

    data class Person(val name: String)
    

    Then the line Person("name") does nothing - it just desclares an unused instance. Person("name second") does the same (generally speaking, as it is the last line in lambda, it implicitly returned as the result of lambda expsession and theoretically, it could be handled later; anyway, that DSL syntax won't be working in general case).

    You need not just declare instances, but also add them to list. So you need to declare some auxilary function (person for instance, to be close to desired syntax) which will do this under the hood:

    class Persons {
        val delegate: MutableList<Person> = mutableListOf()
    
        fun person(name: String, block: Person.() -> Unit = {}) {
            delegate.add(Person(name).also(block))
        }
    }
    
    fun persons(block: Persons.() -> Unit) = Persons().also(block).delegate.toList() //mutation was needed only during construction, afterwards consider preserving immutability
    

    Usage:

    val persons: List<Person> = persons {
        person("name")
        person("name second")
    }