| Games | |
|---|---|
| Amazons | (play) |
| Ataxx | (play) |
| Breakthrough | (play) |
| Cephalopod | (play) |
| Checkers | (play) |
| Connect6 | (play) |
| Dots and Boxes | (play) |
| Footsteps | (play) |
| Kalah | (play) |
| Keryo-Pente | (play) |
| Nine Men's Morris | (play) |
| Othello | (play) |
| Oware | (play) |
| Pah-Tum | (play) |
| Pente | (play) |
| Phutball | (play) |
| Three Musketeers | (play) |
| Articles by Tag | |
|---|---|
| AI | (2) |
| Announce | (33) |
| Ruby | (2) |
| Software Development | (3) |
| Technology | (9) |
| Vying Games | (49) |
Functional Memoize in an Object Oriented World |
|
|
April 13, 2007 at 07:00PM
In Technology, Ruby |
By
eki
2 Comments |
Memoization (not to be confused with memorization) is an optimization technique that most programmers are familiar with, even if the name might sound somewhat foreign. In brief, it's a caching technique where the results of a computationally expensive function are cached to avoid recomputing the same values multiple times. (Oh, the irony. Did I really say "In brief" before writing that?) In functional circles, if I say I'm going to memoize a function, I'm not actually going to hack it until I've added a bunch of ugly one-off caching code that obscures the way the original code worked. I'm not going to modify the original function at all. Rather, I'm going to use a In truly functional languages, this is possible because:
Given the right building blocks one can write a Automatic memoization is obviously a beautiful thing. So it shouldn't be surprising that it's not solely the plaything of functional programmers. It is possible to write Vying Games, Ruby, and MemoizationSince Vying Games is written in Ruby (a language with a slight performance handicap), and includes many computationally intense methods, I've become fairly well acquainted with But first, memoization is a been there, done that in the Ruby world. Here's a list of some of the more interesting implementations:
The What to do with self?In Ruby, we don't really have functions. We have objects with methods. Objects have state, and that state (sometimes) effects the results of method calls. Consider:
If we were to memoize But this isn't a realistic example. If Unfortunately, we really can't know when What to do with mutable return values?Again, objects have state -- including our return values. If we cache mutable objects we leave ourselves open to all kinds of possible bugs. Consider a method that returns a new array every time it's called. When using the unmemoized version it's safe to modify the returned array -- the next time the method is called a brand new array will be returned. However, when the method's memoized, the array is cached and returned with every call. Now, if we modify the returned array, we've changed the value returned by all future calls. This is bad. Really bad. Speaking from experience, it can take hours to track down such bugs. Imagine, we have some working, but slow, code that we'd like to optimize. Suppose, we find a method that's a good candidate for memoization. Let's say this code returns a freshly created, mutable object. What if existing code depends on the fact that its safe to modify the object? We won't be able to use memoize without also rewriting that dependent code. That's ugly. That makes Haskell programmers cry. (Or gloat?) There are a couple possible solutions to this problem. In Ruby, our Another possible solution would be to In the end, I went with the Memoize and Object CreationIf a class of objects are immutable, but object creation is slow or done frequently, memoizing And, of course, in the case where If your class of objects are mutable, the clone trick described above can be useful. Though you won't save any memory, you might be able to save on computation time. A Little Beaten Up, But Still a LookerSo while our beautiful, functional Just be careful if you mess around with it. And, as always, don't forget to benchmark your code. |
Hi, Alexander, thanks for commenting (I cleaned up your formatting -- sorry about that).
I'm still not happy with my own memoize (or I'd post the actual code). I think it's deceptively hard to get a good general solution.
Alexander Botero-Lowry says,
I do memoization all the time in python, though I admit to doing a bit of a check hack like you mentioned being a bad thing. :/ It's such a little test that I tend to ignore it though, only adds 2 lines to the function in the end.
I admit I find memoization as you describe it pretty attractive so I might just write a decorator to do this a bit more elegantly.