From: John Carter Date: 2008-12-02T08:53:57+09:00 Subject: Adventures in Optimization... or why CONST frozen is Good ...or when a language design level optimization is a pessimization. Ruby allows destructive string operations. String instance methods with a "Bang!" at the end. Consider this code. a = ['froot'] b=a.first c = {"d"=>b} Now a[0], b, c["d"] refer to _exactly_ the same string instance > a[0].object_id => -605300798 > b.object_id => -605300798 > c["d"].object_id => -605300798 So if I do a destructive operation on any of them, all are clobbered. a.last.sub!(/oo/,"ui") => "fruit" irb(main):009:0> b => "fruit" irb(main):010:0> c => {"d"=>"fruit"} Traditionally destructive ops have been allowed in languages such as Lisp etc. as an optimization. You don't have to "new" a new object instance if you don't want to. The other day I was optimizing my code, when I decided to hunt unnecessary object allocation. I used my MemoryProfiler snippet to find that String's were by far the most common object I was generating. http://rubyforge.org/snippet/detail.php?type=snippet&id=70 So I extended that to find _which_ was the most common string I was generating. def MemoryProfile::string_duplicates Dir.chdir "/tmp" ObjectSpace::garbage_collect sleep 10 # Give the GC thread a chance tally = Hash.new(0) ObjectSpace.each_object do |obj| next if obj.class != String tally[obj]+=1 end open( LOG_FILE, 'a') do |outf| outf.puts '='*70 outf.puts " String Duplicates report for #{$0} " tally.keys.find_all{|s| tally[s] > 1}.sort_by{|s| tally[s]}.each do |s| outf.puts "#{s}\t#{tally[s]}" end end end The answer, by a long shot, was "U". Somewhere in my code I had the line symbols_needed[symbol_name] = 'U' I could replace that with the symbol :U, but other places that had Good Reasons of using strings would break. Now I have a class CONSTANT... UNDEFINED = 'U'.freeze and symbols_needed[symbol_name] = UNDEFINED Of course, if anywhere I apply a destructive op to one of those thousands of references, my code will die. Bit at least the "freeze" will cause a loud and messy death, not a subtle and hidden bug. So as I said at the start, the optimization to allow the occasional destructive op to a string... can be a pessimization in every case where you assign a string literal. a= "froot" => "froot" irb(main):002:0> a.object_id => -605331808 irb(main):003:0> a= "froot" => "froot" irb(main):004:0> a.object_id => -605352198 John Carter Phone : (64)(3) 358 6639 Tait Electronics Fax : (64)(3) 359 4632 PO Box 1645 Christchurch Email : john.carter@tait.co.nz New Zealand