def test_independence
first = "3" + "4"
second = first + "5"
third = "2" + second
assert_equal("34", first.to_s)
assert_equal("345", second.to_s)
assert_equal("2345", third.to_s)
end
Ouch. I fixed it by making DelayString only know a left and a right part. It cleaned the code up quite a bit. I factored out Promise because it made the code a little less readable. The resulting code is much simpler:
class DelayString
def initialize(oneString, anotherString)
@left = oneString
@right = anotherString
end
def +(another)
DelayString.new(self, another)
end
def to_s()
return @result unless @result.nil?
to_process=[self]
@result=String.stream_contents do |out|
until (to_process.empty?)
current=to_process.pop
current.process(to_process,out)
end
end
end
def process(to_process,io)
to_process.push(@right)
to_process.push(@left)
end
end
class String
def self.stream_contents(&monadic)
StringIO.open() do |io|
monadic.call(io)
io.string
end
end
def +(another)
DelayString.new(self, another)
end
def process(to_process,io)
io << self
end
end
All of our tests run. DelayString is stateless (minus caching of the result). There's still improvements to be made, but the code is simpler and easier to understand. The performance did take a hit. It's twice as slow (43.94s) as the previous version. Not to worry it still beats normal concatenation by a large margin. I'll take the performance hit for more readable code anyday!
No comments:
Post a Comment