Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize String Concatenation #104

Closed
Distractic opened this issue Nov 5, 2021 · 1 comment
Closed

Optimize String Concatenation #104

Distractic opened this issue Nov 5, 2021 · 1 comment
Labels
Type: Bug Something isn't working correctly.

Comments

@Distractic
Copy link
Contributor

Distractic commented Nov 5, 2021

Description

In several place of modules, the concatenation of string can decrease the performance.
Currently, the concatenation is make by the operator +=. This is not a problem for the inline concatenation "a" + "b" + "c",
but when it's not, the compiler creates several StringBuilder instance.

So, below, the explanation sent in discord server :

When you add two string, this is the compiled result :

val a = "a"
val b = "b"
val c = "c"
println(a + b + c) // StringBuilder(a).append(b).append(c).toString()

So, here you can see, there is no issue about the performance, because an inline concatenation of string create an once StringBuilder

But, when it's not inline, for each concatenation, a new StringBuilder will be create

val a = "a"
a += "b" // a = StringBuilder(a).append("b").toString()
a += "c" // a = StringBuilder(a).append("c").toString()
println(a)

Or if there is loop, condition, it's the same case

var a = "a"
if(Random.nextInt() == 2) {
   a += "b" // a = StringBuilder(a).append("b").toString()
}
a += "c" // a = StringBuilder(a).append("c").toString()
listOf(1, 2 ,3).forEach {
    a += it.toString() // a = StringBuilder(a).append(it).toString() (x3)
}

println(a)

In the code i seen this for example

list.joinToString { // StringBuilder create for the result
var x = "..;"

if(..) {
  x += "..." // new StringBuilder created
}
// etc.
x
}

A joinToString use an instance of StringBuilder, to concat without performance issue the result of each iteration
BUT, if you provoke the creation of a new StringBuilder in the iteration, so you loss all advantage of joinToString and StringBuilder

Code location

I post here some (not all) part of code concerned by this issue

annotation-processor-1
annotation-processor-2

extra-modules

kord-extension-1
kord-extension-2

etc.

To find all, i advice to use the option in IntelliJ Find in Files with the value += "

Solution

There is two choices to resolve that.

  1. Use the method buildString { }
    The method buildString allows to have a StringBuilder as a receiver variable
println(buildString {
 append("a")
 append("b")
 // etc.
})
  1. Use directly a new instance of StringBuilder
    Same than first solution, but you need to write the variable
val builder = StringBuilder()
builder .append("a")
builder .append("b")
 // etc.
println(builder.toString())
})

For the list and the method joinToString, if you concat in the joinToString, prefer use a StringBuilder and a forEach instead

@Distractic Distractic added the Type: Bug Something isn't working correctly. label Nov 5, 2021
@gdude2002 gdude2002 changed the title Loss of performance when concate Strings Optimize String Concatenation Feb 2, 2022
@gdude2002
Copy link
Member

It's done - completely destroyed any usage of += with strings in KordEx.

DRSchlaubi pushed a commit to mikbot/kord-extensions that referenced this issue Aug 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug Something isn't working correctly.
Projects
None yet
Development

No branches or pull requests

2 participants