Search code examples
kotlinimmutabilitybuildermutability

Why shouldn't builder pattern implementations be immutable?


Consider the following Kotlin implementation of a string builder:

class StringBuilder {
    private val items = mutableListOf<String>()

    fun append(item: String): StringBuilder {
        items.add(item)
        return this
    }

    override fun toString(): String {
        return items.joinToString("")
    }
}

The internal implementation of the StringBuilder requires a mutable list of items, but if you wanted to take immutability seriously, you could easily refactor this to be completely immutable; for example:

class StringBuilder(private val items: List<String> = emptyList()) {

    fun append(item: String): StringBuilder {
        return StringBuilder(items + item)
    }

    override fun toString(): String {
        return items.joinToString("")
    }
}

According to Wikipedia, listed under Disadvantages

Builder classes must be mutable.

This clearly isn't the case; as demonstrated, a builder can be designed to be completely immutable, and the fact that this statement is listed under "Disadvantages" would suggest that it would be advantageous for builders to be immutable.

So, I was wondering if there are any specific reasons why builder implementations should be mutable?

I could only think of one reason - the garbage collection overhead for an immutable builder will be higher as new instances of the builder have to be returned each time.


Solution

  • Disadvantages of the Builder pattern include: (3)

    • ...
    • Builder classes must be mutable.
    • ...

    The referenced presentation in that Wiki for that bullet point does not say "builder classes must be mutable" or list it as a disadvantage. So I find the placement of that reference to be misleading.

    I think your point about garbage collection overhead is the only disadvantage in languages like Kotlin? (Aside from the inconvenience of ensuring you deep copy your fields in complex builders)