I’ve got a `class Foo` and a `class FooBuilder`. t...
# getting-started
y
I’ve got a
class Foo
and a
class FooBuilder
. the
FooBuilder
takes some parameters and tries to construct a
Foo
. then I can make a
constructor
in
Foo
that takes a
FooBuilder
. now what I’d like to do is disallow creating a
FooBuilder
from outside the file (to avoid exposing the implementation and to avoid intermediate state and to avoid writing
private
everywhere in
FooBuilder
), and then have a function that creates a
FooBuilder
, and returns the result of the build (maybe
Foo.companion.invoke
) but now I have to put the
FooBuilder
definition inside
Foo
, or else I’m exposing the private-in-file class
FooBuilder
. but that adds an extra indentation level and massive amounts of unrelated code to
Foo
. is there any other way?
e
just make
class FooBuilder internal constructor()
if you don't want it constructed externally?
y
oh, nice! other than still having to annotate everything in
FooBuilder
as
private
, this solves it. thanks.
is there a
@Suppress
annotation I can use for the class to silence the
could be private
warnings?
e
that's not a compiler warning, is it?
y
ah, maybe I’m wrong and it’s an IntelliJ thing?
e
I know there's Detekt rules for that, I don't touch the IDE a whole ton so I'm not sure what its inspections are
s
Are you sure you even need a FooBuilder? The pattern makes sense in Java, but in Kotlin constructors have named and optional parameters. So if you have a FooBuilder because you started of with a Java codebase you might want to simply replace the whole pattern which said advanced constructors.
y
in this case, I do. I'm not using the builder to cover up an abundance of optional parameters. I'm doing it because there is a (very) non-trivial amount of initialization to do. the
Foo
is pretty much just the result of the computation
I think Builder may be a misleading name here
s
it*s all good. I just recently wrote a blog post arguing that you don't need Builders in Kotlin 😅 Of course I was thinking about DTOs with @Lombok annotations.
a
I might be out of context. But I find myself needing Builders for Java consumers.
👍 1
e
they're also better for maintaining binary compatibility
🤔 1
g
You can make your builder a function in the
Foo
companion object
that takes a lambda that uses a builder- or configuration-object as a receiver.
Copy code
class Foo {
 ...
 companion object {
    fun build (FooBuilder.() -> Unit) : Foo {
      ...
    }
  }
}
The constructor of
FooBuilder
can be private because no-one than this
build
-function is ever creating an instance of it.
e
@Stephan Schröder adding a parameter is a binary compatibility break, even if it's optional, even with
@JvmOverloads
. see https://jakewharton.com/public-api-challenges-in-kotlin/:
Even if you are only appending properties to avoid breaking the component functions, these two signatures always change.
real-world example: https://github.com/Kotlin/kotlinx.serialization/releases/tag/1.0.0-RC kotlinx.serialization went from
JsonConfiguration(...)
to
Json(JsonBuilder.() -> Unit)
pre-1.0 to ensure that that they could continue to evolve post-1.0