Useful potential method: `joinToString`, but inste...
# stdlib
d
Useful potential method:
joinToString
, but instead of a
transform
lambda, it takes
build: StringBuilder.(T) -> Unit
. That avoids creating intermediate strings for each element if multiple
append
calls would be more efficient.
Currently looking at a good use-case in which the string is built with
StringBuilder
, but the loop has an
isNotEmpty
check to decide whether or not to include the separator.
e
I have wanted that on a few occasions, but
StringBuilder
receiver is too powerful, because the block can
insert(0, ...)
and break the separation
maybe
Appendable
though?
d
Appendable
looks like it should work just as well.
e
(but the Kotlin interface requires you to stringify inputs first, which brings us back to the original issue with unnecessary intermediates)
d
Which interface is requiring that?
(which is basically the same signature as the Java interface, minus
throws IOException
)
d
Is the issue that it doesn't also have
append
for primitives and
Any
? Are those implemented more efficiently than calling
toString
? I would doubt it.
e
as an almost-as-concise workaround, if you have a fixed delimiter you could just always append it and then truncate it 🙂
Copy code
entries.fold(StringBuilder()) { sb, (key, value) -> sb.append(key).append('=').append(value).append(", ") }.dropLast(2)
d
You can also have something like the original suggestion but have the standard library always supply an empty builder into the lambda, then copy the result over. So it'll be managing two string builders.
d
Is that any more efficient than just using the existing
joinToString
and
buildString
manually? The goal is to not create intermediate strings and copying.
d
Yeah sure, the copying is still there but I've reduced the number of allocations to just 2 ish.
Whilst still maintaining safety, so to speak
d
Using
Appendable
preserves safety while matching the performance of a hand-written
buildString
and loop.
The
fold
can work, but it's much more difficult to read to understand what it's trying to do compared to
joinToString
, or update it safely (the
dropLast
must match the separator size), and I can't tell from the documentation how efficient
StringBuilder.dropLast
actually is.
d
Appendable requires a string though, so you pay for the conversion to strings anyway.
d
Under the hood,
StringBuilder.append(int)
still calls
toString
, so with a few extensipn methods on
Appendable
, we end up with the same API and the same number of strings.
i
Note that there's also joinTo function, that takes an Appendable. However it still transforms each element to a string before appending it.