0

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"))
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
DTechnlogy
  • 320
  • 4
  • 12

2 Answers2

2

Not quite exactly as you have but should be able to use something like

data class Person(var name: String? = null)

class Persons : ArrayList<Person>() {
    fun person(block: Person.() -> Unit) {
        val person = Person().apply(block)
        add(person)
    }
}

fun persons(block : Persons.() -> Unit): Persons = Persons().apply(block)

fun main() {
    val personList = persons {
        person {
            name = "John"
        }
        person {
            name = "Jane"
        }
    }

    println(personList)
}

(This could be expanded then to use some kind of builder pattern to allow use of immutable vals in the data class)

John O'Reilly
  • 10,000
  • 4
  • 41
  • 63
2

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")
}