ilya.gorbunov
03/10/2021, 12:33 PMbuildList
, buildSet
and buildMap
, introduced as experimental in 1.3.70? Do you use them in your code? What are your impression of them?Thomas
03/10/2021, 12:45 PMbuildList
a lot in my code now, it is really useful. The code looks much better with it. I don’t really use the other two build functions for Set and Map.Zhelenskiy
03/10/2021, 12:57 PMbuildList
and buildMap
a lot while I almost don't use buildSet
. Some buildMutable...
functions may also be helpful but they can be done with specifying implementation: ArrayList().apply { ... }
. However, there are both mutable and read-only analogues for listOf
, mapOf
, so it is better to have both ones here too.wasyl
03/10/2021, 1:11 PMbuildList
a lot. I like it mostly, although I hear some complaints that it’s less readable than
listOf(firstElement)
+ secondElement
+ thirdElement
and it’s easy to have an expression inside but forget to wrap it in an add(…)
call. With +
from the example above it’d be much more difficult to unintentionally not add somethingDominaezzz
03/10/2021, 5:45 PMnkiesel
03/10/2021, 6:57 PMbuildList
, we should also have the other primary constructs like sets and maps handled for consistency. Which brings up the question about `buildArray`: do we need that?
• there is a sweet-spot for buildXXX where the block is complicated enough to e.g. require some variables or statements but not so complicated that we loose track of what an add
or put
call operates on. I sometimes wished I could use val l = buildList { mylist -> ...; myList.add(...) }
louiscad
03/10/2021, 10:48 PMthis
to use the +=
operator, or use add
, but I still like buildList
and used it in a few places, though the experimental status didn't encourage me to use it more.Zac Sweers
03/11/2021, 1:03 AMZac Sweers
03/11/2021, 1:04 AMdave08
03/11/2021, 2:57 AMMarc Knaup
03/11/2021, 6:05 PMbuild*
functions.
• I rarely have the need. Most lists etc. are created by function chains anyway.
• In cases when I’ve tried the builders they made code more difficult to read rather than easier. Partially because thee are add()
calls scattered around and you don’t immediately see the receiver.
• In many cases it feels wrong to introduce a scope and indent code just to create a list. The list is often a side-effect or (partial) result of another primary intent. Indenting it focuses the code on creating a list, not of the primary intent.
For buildString
it’s different somehow. Maybe because it’s way more common? And append
is clearer in such contexts? And creating the String is usually the primary intent of the code within the block.
I’ve run a quick search over my entire Kotlin codebase. There isn’t a single instance left where I use it.
I guess there are good cases for these builders. I just haven’t found some in my back-end & front-end code yet.Fleshgrinder
03/11/2021, 10:29 PMbuildMap
very often.Fleshgrinder
03/11/2021, 10:35 PMbuild*
functions over what you have is that they take the expected size and allow you to build collections in the most efficient way without resizing. They are not meant to contain complex logic (but obviously can).
A situation where I like to use them is in conjunction with `vararg`: fun f(s: String, vararg ss: String) = buildList(1 + ss.lenght) { add(s); addAll(ss.toIterable()) }
wasyl
03/12/2021, 8:19 AMZhelenskiy
03/12/2021, 8:36 AMbuildArray
different from just Array
constructor? Don't think so. You have to specify size and values per index. You have no add
method for `Array`s.
• You can do the following:
val l = buildList {
val myList = this
myList.add(...)
}
Fleshgrinder
03/13/2021, 9:14 PMJavier
03/24/2021, 2:21 PMilya.gorbunov
03/25/2021, 2:12 PMJavier
03/25/2021, 2:17 PMilya.gorbunov
03/25/2021, 2:22 PMlouiscad
03/26/2021, 1:46 PMbuildList
in a Gradle plugin and possibly libraries, but I'm not sure if it's safe when it comes to forward compatibility since the RequiresOptIn annotation only says it's experimental overall.louiscad
03/31/2021, 7:02 AMbuildList
lambda, because of that annoying indent:
buildList {
if (whatever) add(
Stuff(
...
)
)
...
}
with unary plus, it becomes the following:
buildList {
if (whatever) +Stuff(
...
)
...
}
I guess that's what the unary plus operator has been designed for, and there's a precedent in kotlinx.html.
Is that something that was ever considered for buildList
and friends @ilya.gorbunov?Fleshgrinder
03/31/2021, 7:54 AMthis
in all of the build
functions as it is a source of many bugs. Having the receiver as first argument would automatically solve your issue as well since you'd have it + Stuff
Dominaezzz
03/31/2021, 8:01 AMlouiscad
03/31/2021, 8:02 AMFleshgrinder
04/24/2021, 5:04 PMfun String.doSomething() = buildString {
forEach { /* or something similar that is available on both String and StringBuilder */ }
}
Solution:
fun String.doSomething(): String {
val it = this
return buildString {
it.forEach { /*...*/ }
}
}
I stand by what I said above, this would avoid these issues altogether:
fun String.doSomething() = String { it ->
forEach { c -> it.append(c).append(c) }
}
Zhelenskiy
04/24/2021, 5:17 PMFleshgrinder
04/24/2021, 5:19 PMStringBuilder
as receiver of buildString
. The problem is that the sources often have the same functions, and this confuses people. I already see the same happening with buildList
and friends.
fun <E> Iterable<E>.doSomething() = buildList { forEach { /* ouch */ } }