For the complete documentation index, see llms.txt. This page is also available as Markdown.

StringBuilder

Fast, mutable string building with first-class BoxStringBuilder support, compile-time folding, and automatic runtime optimizations.

Available since BoxLang 1.15.0

String concatenation looks simple until it's on a hot path. Because Java (and therefore BoxLang) strings are immutable, joining two strings always creates a new object and copies both buffers. In a tight loop building a large payload—HTML fragments, JSON snippets, SQL strings, log lines—that cost compounds quickly.

BoxLang 1.15.0 addresses this with four complementary improvements that work together transparently:

  1. BoxStringBuilder — a first-class, mutable string buffer type

  2. &= in-place append semantics for builder values

  3. Compiler self-assignment rewritedata = data & chunkdata &= chunk

  4. Compile-time literal folding & auto-switching runtime concat strategy

For most code you benefit automatically. For hot loops and large accumulators, reaching for BoxStringBuilder gives you full control.


Why StringBuilder?

// ❌ Every &= creates a NEW String and copies the old one
result = ""
for ( item in myList ) {
    result = result & item & ", "
}

// ✅ BoxStringBuilder appends in-place — one buffer, no copies
sb = sb{}
for ( item in myList ) {
    sb.append( item ).append( ", " )
}
result = sb.toString()

From 2 to 8 string segments in 100,000-iteration benchmarks:

  • String concat is faster for exactly 2 strings

  • Break-even is around 3 segments

  • Beyond that, builder scales ~4.2× better than plain concat

  • BoxLang automatically uses a StringBuilder-backed path for 4 or more segments


Creating a BoxStringBuilder

There are three equivalent creation forms:

The sb{ ... } literal (and its stringbuilder{ ... } alias) accepts any expression, not just string literals. The expression is evaluated, converted to a string, and used to seed the buffer:

A variable named sb or stringbuilder is still just a variable when used as a plain identifier. The parser only treats them specially when immediately followed by braces: sb{ ... } or stringbuilder{ ... }.


Member Method API

BoxStringBuilder uses 1-based positional indexing throughout — consistent with BoxLang's array and string conventions.

Mutation

Method
Description

append( value )

Append a value to the end of the buffer

prepend( value )

Insert a value at the beginning

insert( position, value )

Insert at a 1-based position

delete( start, end )

Delete characters from start to end inclusive (1-based)

replace( start, end, value )

Replace the range [start, end] with a new value

reverse()

Reverse the entire character sequence in place

clear()

Reset the buffer to empty

trim()

Remove leading and trailing whitespace

Inspection

Method
Description

left( count )

Return the leftmost count characters

right( count )

Return the rightmost count characters

mid( start [, count ] )

Substring from 1-based start, optional count

find( substring [, start [, noCase ] ] )

Find a substring, returns 1-based position or 0

contains( substring [, noCase ] )

true if the buffer contains the substring

startsWith( prefix )

true if the buffer starts with the given prefix

endsWith( suffix )

true if the buffer ends with the given suffix

length()

Current length of the buffer in characters

isEmpty()

true if the buffer contains no characters

toString()

Materialize the buffer as an immutable Java String

All mutation methods return this for fluent chaining:

Examples


The &= Operator

When the left-hand side of &= is a BoxStringBuilder (or a raw java.lang.StringBuilder), BoxLang performs an in-place append instead of creating a new string:

This is semantically equivalent to sb.append( ", World" ).append( "!" ) and avoids any allocation or reference change.


Common Patterns

Building large strings in loops

Building JSON fragments

Stable reference identity

Because &= mutates BoxStringBuilder in place, any reference already pointing to the same buffer sees updated content:

Template rendering


Compiler Optimizations

Literal folding at compile time

Contiguous string literals in a concat chain are merged by the compiler before the code runs:

Mixed expressions are partially folded — adjacent literal segments are combined while dynamic segments are preserved:

Self-assignment rewrite

The compiler detects patterns where the explicit concat result is assigned back to the same target and rewrites them to the compound form:

This rewrite applies to identifier targets (data), dot-access targets (variables.data, obj.field), and array-access targets (arr[1]). When data is a BoxStringBuilder, the compound form triggers in-place append.


Runtime Concat Strategy

At runtime, concat expressions are lowered depending on segment count:

Segments
Strategy

0–1

Trivial return

2–3

Direct String concat (fastest for short chains)

4 or more

StringBuilder-backed path with pre-computed initial capacity

This automatic switching means you get optimal behavior with no manual tuning for expression chains and string interpolation:

Both are lowered to:


Java Interoperability

Wrapping a Java StringBuilder

BoxStringBuilder member methods are not injected onto raw java.lang.StringBuilder instances to avoid mixing 1-based (BoxLang) and 0-based (Java) positional semantics. Wrap the Java instance first:

Silent coercion to String

Passing a BoxStringBuilder anywhere a String is required automatically calls toString():


Practical Guidance

Use plain concat when:

  • You are joining just 2–3 values

  • The code is not on a hot path or in a loop

Use BoxStringBuilder when:

  • You append repeatedly inside loops

  • You build large payloads incrementally (HTML, JSON, SQL, CSV, logs)

  • You need stable reference identity while mutating content

  • You want explicit control over buffer capacity

Prefer compound concat:

  • Write data &= piece for mutable accumulation

  • Legacy data = data & piece patterns are now automatically rewritten by the compiler in most cases

Let the runtime handle it:

  • Any concat expression with 4+ segments is optimized automatically — no changes needed


Performance Data

Benchmark setup: 100,000 iterations, comparing plain string grow versus StringBuilder append, segment count 2–8.

Segments
Plain Concat
StringBuilder
Winner

2

✅ Faster

&

3

~Equal

~Equal

Either

4

Slower

✅ Faster

sb

6

Much slower

✅ Faster

sb

8

~4.2× slower

✅ Faster

sb

From 2 to 8 strings, concat growth is roughly 4.2× steeper than builder growth. BoxLang uses the builder path automatically at 4+ segments.


BIF Reference

stringBuilderNew( [initial], [capacity] )

Creates a new BoxStringBuilder.

Argument
Type
Default
Description

initial

any

""

Initial value or a raw java.lang.StringBuilder to wrap

capacity

numeric

16

Initial buffer capacity in characters (hint, not a hard limit)

Literal Syntax

Both are parsed identically and create a BoxStringBuilder seeded with the evaluated expression.


Last updated

Was this helpful?