From: Kurt Stephens Date: 2010-03-27T08:48:43+09:00 Subject: [ruby-core:29057] Re: [Feature #889] erb.rb should use Array and << for eoutvar and not String and concat Jeremy Kemper wrote: > On Fri, Mar 26, 2010 at 11:45 AM, Kurt Stephens wrote: >> Issue #889 has been updated by Kurt Stephens. >> >> >> This is not a good idea, because the expression value Strings accumulated in the Array must be protected from mutation. >> ERB expressions can have side-effects. >> >>
>> SOME_STRING = 'foobar'
>> def foo
>>  SOME_STRING
>> end
>> def bar
>>  SOME_STRING.sub!(/bar/, '')
>>  SOME_STRING
>> end
>> # ERB GENERATED CODE: from "<%= foo %><%= bar %>"
>> eoutvar = [ ]
>> eoutvar << foo
>> eoutvar << bar
>> eoutvar.join('')
>> 
> > I disagree. That's based on a loose assumption that <%= ... %> behaves > like #{...}. > String#<<(x) "appends by value", Array#<<(x) "appends by reference". The subsequent Array#join is affected by mutations to the argument, the former is not. Ruby Strings are passed and returned by reference, not by value. The proposal introduces aliasing problems that did not exist before. IMO, it's counter-intuitive. <%= ... %> currently behaves as if it's embedded in a stream, similarly "#{...}" interpolations are evaluated left-to-right. String#<< and IO#<< have stream-like semantics and are immune to argument aliasing, Array#<< and the subsequent Array#join behave differently. The example above would work differently, if IO === eoutvar, than if Array === eoutvar. If we don't care about preserving semantics, then it's not an issue. I'd prefer that <%= ... %> continues to behave like "#{...}", both have implicit order-of-evaluation and are immune to aliasing. KAS