<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Alice, Bob and Mallory: String concatenation in Ruby</title>
    <link>http://alicebobandmallory.com/articles/2010/02/02/string-concatenation-in-ruby</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>metasyntactics</description>
    <item>
      <title>String concatenation in Ruby</title>
      <description>&lt;p&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/thumb/5/5a/Knit-schematic.png/200px-Knit-schematic.png" style="display: inline-block; float:right"/&gt;
There's no &lt;code&gt;StringBuilder&lt;/code&gt; class in Ruby because the &lt;a href="http://ruby-doc.org/core/classes/String.html"&gt;String&lt;/a&gt; class has the &lt;a href="http://ruby-doc.org/core/classes/String.html#M000807"&gt;&amp;lt;&amp;lt;&lt;/a&gt; for appending. The problem is that not every Ruby programmer seems to be aware of it. Recently I've seen &lt;code&gt;+=&lt;/code&gt; being used to append to strings where &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; would have been a much better choice.&lt;/p&gt;

&lt;p&gt;The problem with using &lt;code&gt;+=&lt;/code&gt; is that it creates a new String instance and if you do that in a loop you can get really horrible performance.&lt;/p&gt;

&lt;p&gt;If you are dealing with an array you don't even have to use &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; because &lt;a href="http://ruby-doc.org/core/classes/Array.html#M002182"&gt;Array#join&lt;/a&gt; is even faster and shows intent in a nice way.&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;15&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;require &lt;span style="background-color:#fff0f0;color:#D20"&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;span style=""&gt;benchmark&lt;/span&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;array_of_rnd_strings=(&lt;span style="color:#00D;font-weight:bold"&gt;0&lt;/span&gt;...&lt;span style="color:#00D;font-weight:bold"&gt;262144&lt;/span&gt;).map{&lt;span style="color:#00D;font-weight:bold"&gt;65&lt;/span&gt;.+(rand(&lt;span style="color:#00D;font-weight:bold"&gt;25&lt;/span&gt;)).chr}&lt;tt&gt;
&lt;/tt&gt;                                 .join.scan(&lt;span style="background-color:#fff0ff"&gt;&lt;span style="color:#404"&gt;/&lt;/span&gt;&lt;span style="color:#808"&gt;.{1,8}&lt;/span&gt;&lt;span style="color:#404"&gt;/&lt;/span&gt;&lt;span style="color:#C2C"&gt;m&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span style="color:#036;font-weight:bold"&gt;Benchmark&lt;/span&gt;.bm &lt;span style="color:#080;font-weight:bold"&gt;do&lt;/span&gt; |benchmark|&lt;tt&gt;
&lt;/tt&gt;  benchmark.report &lt;span style="color:#080;font-weight:bold"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    str=array_of_rnd_strings.join&lt;tt&gt;
&lt;/tt&gt;  &lt;span style="color:#080;font-weight:bold"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  benchmark.report &lt;span style="color:#080;font-weight:bold"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    str2=&lt;span style="background-color:#fff0f0;color:#D20"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    array_of_rnd_strings.each &lt;span style="color:#080;font-weight:bold"&gt;do&lt;/span&gt; |s|&lt;tt&gt;
&lt;/tt&gt;      str2&amp;lt;&amp;lt;s&lt;tt&gt;
&lt;/tt&gt;    &lt;span style="color:#080;font-weight:bold"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span style="color:#080;font-weight:bold"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  benchmark.report &lt;span style="color:#080;font-weight:bold"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    str3=&lt;span style="background-color:#fff0f0;color:#D20"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    array_of_rnd_strings.each &lt;span style="color:#080;font-weight:bold"&gt;do&lt;/span&gt; |s|&lt;tt&gt;
&lt;/tt&gt;      str3+=s&lt;tt&gt;
&lt;/tt&gt;    &lt;span style="color:#080;font-weight:bold"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span style="color:#080;font-weight:bold"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span style="color:#080;font-weight:bold"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


The array_of_rnd_strings is an array of 32768 8 characters long random strings.
&lt;br/&gt;
&lt;br/&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;td&gt;&lt;b&gt;user&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;system&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;total&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;real&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;    
&lt;td&gt;0.030000&lt;/td&gt;&lt;td&gt;0.000000&lt;/td&gt;&lt;td&gt;0.030000&lt;/td&gt;&lt;td&gt;(  0.027184)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;0.160000&lt;/td&gt;&lt;td&gt;0.010000&lt;/td&gt;&lt;td&gt;0.170000&lt;/td&gt;&lt;td&gt;(  0.190277)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;106.020000&lt;/td&gt;&lt;td&gt;0.300000&lt;/td&gt;&lt;td&gt;106.320000&lt;/td&gt;&lt;td&gt;(113.457793)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;br/&gt;&lt;/p&gt;

&lt;p&gt;The performance of &lt;code&gt;+=&lt;/code&gt; was even &lt;strong&gt;worse&lt;/strong&gt; than I imagined!&lt;/p&gt;</description>
      <pubDate>Tue, 02 Feb 2010 00:04:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:08c4064d-9cef-4bee-8988-ea89961d87a2</guid>
      <author>Jonas Elfström</author>
      <link>http://alicebobandmallory.com/articles/2010/02/02/string-concatenation-in-ruby</link>
      <category>Ruby</category>
    </item>
    <item>
      <title>"String concatenation in Ruby" by Jimmy</title>
      <description>&lt;p&gt;Sweet&lt;/p&gt;</description>
      <pubDate>Tue, 06 Apr 2010 15:10:42 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:77a1b8c8-f175-4fb3-bd16-d308d1fd15e1</guid>
      <link>http://alicebobandmallory.com/articles/2010/02/02/string-concatenation-in-ruby#comment-4029</link>
    </item>
  </channel>
</rss>
