From: "ara.t.howard" Date: 2008-12-02T08:57:54+09:00 Subject: Re: Adventures in Optimization... or why CONST frozen is Good On Dec 1, 2008, at 4:53 PM, John Carter wrote: > ...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 > > thanks john. interesting. a @ http://codeforpeople.com/ -- we can deny everything, except that we have the possibility of being better. simply reflect on that. h.h. the 14th dalai lama