# ANN: StringBuilders.jl

**URL:** <https://discourse.julialang.org/t/ann-stringbuilders-jl/9223>\
**Category:** Community\
**Tags:** announcement\
**Created:** [February 21, 2018, 4:05am UTC](https://discourse.julialang.org/t/ann-stringbuilders-jl/9223 "2018-02-21T04:05:03Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![davidanthoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davidanthoff/32/223493_2.png) [@davidanthoff](https://discourse.julialang.org/u/davidanthoff)\
**Post date:** [February 21, 2018, 4:05am UTC](https://discourse.julialang.org/t/ann-stringbuilders-jl/9223/1 "2018-02-21T04:05:03Z")

</div>

[StringBuilders.jl](https://github.com/davidanthoff/StringBuilders.jl) is a very small package that provides a convenient API for building up strings, similar to what you have in .Net and lots of other languages.

This package is mainly an API exploration. You can get more or less the same functionality by creating an `IOBuffer`, writing to that and at the end taking the buffer and converting it into a `String`. But at least I can never remember all the details of that for more than one day, and then have to google things. So, this is an attempt to provide a more streamlined API for the same use case. Any feedback would be welcome!

I don’t think I will do anything beyond what is there with this package. But it might be interesting to play around with different implementations of a `StringBuilder` and benchmark them against each other. [This](http://codingsight.com/stringbuilder-the-past-and-the-future/) article has an interesting discussion how the implementation in .Net was changed over time. If anyone wants to experiment with those kind of things, please open an issue over in the package so that we can briefly discuss a good strategy for inclusion of experiments like that.

---

<div class="post-metadata">

**Author:** ![davidanthoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davidanthoff/32/223493_2.png) [@davidanthoff](https://discourse.julialang.org/u/davidanthoff)\
**Post date:** [February 21, 2018, 6:28pm UTC](https://discourse.julialang.org/t/ann-stringbuilders-jl/9223/2 "2018-02-21T18:28:08Z")

</div>

One more thing: if someone has an opinion about [https://github.com/davidanthoff/StringBuilders.jl/issues/2](https://github.com/davidanthoff/StringBuilders.jl/issues/2), please let me know! It is not clear to me what the right function is for adding stuff to the string. Right now I use `append!`, but I’m not clear whether something like `print` or `write` or something else would be more appropriate.

---

<div class="post-metadata">

**Author:** ![samoconnor](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/samoconnor/32/1802_2.png) [@samoconnor](https://discourse.julialang.org/u/samoconnor)\
**Post date:** [February 22, 2018, 9:20pm UTC](https://discourse.julialang.org/t/ann-stringbuilders-jl/9223/3 "2018-02-22T21:20:48Z")

</div>

I was thinking about a mutable `AbstractString` type along the lines of [`uio.h: struct iovec`](https://github.com/torvalds/linux/blob/master/include/uapi/linux/uio.h#L17-L21). It would be like a lazy string builder. Rather than allocating new strings, it would just keep a list of the strings that were appended. A new concatenated string would be created by doing `convert(String, ...)`. Or, if the string was written to an `IO` stream, the new string would never need to be created. The `write` function could just write each collected item in turn.

_(My use case is [splicing changes into JSON texts](https://discourse.julialang.org/t/announce-a-different-way-to-read-json-data-lazyjson-jl/9046/9))_

```julia
struct SplicedString
    v::Vector{AbstractString}
end

```

`append!` just adds to the list:

```julia
append!(s::SplicedString, x::AbstractString) = push!(s.v, x)

```

`splice`-ing a `String` creates a `SplicedString` using `SubStrings` of the original string:

```julia
splice(s::AbstractString, i, x::AbstractString) =
    SplicedString([SubString(s, 1, i), x, SubString(s, i+1)])

```

`splice!` would figure out which item in `s.v` contains index `i`, then splice `x` into that item:

```julia
splice!(s::SplicedString, i, x) = ...

```

```julia
write(io::IO, s::SplicedString) = write(io, s.v...)

```

---

<div class="post-metadata">

**Author:** ![davidanthoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davidanthoff/32/223493_2.png) [@davidanthoff](https://discourse.julialang.org/u/davidanthoff)\
**Post date:** [February 22, 2018, 9:30pm UTC](https://discourse.julialang.org/t/ann-stringbuilders-jl/9223/4 "2018-02-22T21:30:19Z")

</div>

That is a bit similar to the new .Net implementation, but uses a vector instead of their linked list like thing, and I think they also combine very short strings right away into one buffer.

My guess is that each of these might be really good for a specific use case?

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [February 22, 2018, 9:47pm UTC](https://discourse.julialang.org/t/ann-stringbuilders-jl/9223/5 "2018-02-22T21:47:40Z")

</div>

This sounds much like the `RopeString` type that was removed from base (and put into LegacyStrings).  
(I like the idea, personally)

---

<div class="post-metadata">

**Author:** ![samoconnor](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/samoconnor/32/1802_2.png) [@samoconnor](https://discourse.julialang.org/u/samoconnor)\
**Post date:** [February 25, 2018, 10:30am UTC](https://discourse.julialang.org/t/ann-stringbuilders-jl/9223/6 "2018-02-25T10:30:22Z")

</div>

I’ve started fleshing out the [`SplicedString`](https://github.com/samoconnor/LazyJSON.jl/blob/master/src/SplicedStrings.jl) thing a bit.

I’ve done the indexing using sparse 64-bit indexes (`fragment_number << 40 | index`) which means that `next`,`nextind`, `prevind` etc are all constant time. I haven’t done any benchmarks yet, but so far it feels like it should be fairly efficient.
