From: Joe Cheng Date: 2003-09-03T16:41:19+09:00 Subject: holub and OOP flavors Just want to surface this link to everyone involved in the (rather large) subthread of OOP flavors: http://www.javaworld.com/javaworld/jw-07-1999/jw-07-toolbox_p.html james_b posted it as a footnote but I thought people might easily miss it. I read this 6-part series a couple of years ago and it really challenged the way I thought about OO. While Holub is certainly "extreme" in his views, I think he does make some very illuminating--and often convincing--arguments. (It's a long series, but very worth it IMO...) What finally resolved it for me was reading some of the articles Bill Venners wrote on artima.com about OOP. He said something to the effect of, "OOP is for programmers, not computers." In other words, the level of success of a particular design is generally defined by how effective that design is in managing complexity. If your program has four simple datatypes with fairly inflexible semantic definitions (let's call them, oh, String, Fixnum, Array and Hash) and 99 use cases involving those datatypes, it probably makes sense to have the datatypes operating on the data. If, on the other hand, you have 99 arbitrarily complex datatypes that are very likely to change from release to release--say you're representing bank accounts once served by 40 different legacy systems--and four very concrete use cases (withdrawal, deposit, transfer, close), then it probably makes sense for your 99 types to have the actions hanging off them. OK, those were pretty bad examples... :) The point is, I *don't* think the following should be the primary factors that decide whether x.foo(y) or y.fooTo(x) is best: * x.foo(y) is more natural because it's x that does the fooing. * In the Real World, you don't tell a y to fooTo x, you just foo the y with x. * It just feels wrong, I don't know why. Instead I think the thought process should sound more like: * x is more likely to change in the future, so I would like to keep its implementation particularly opaque and its public interface particularly compact. Therefore I will choose x.foo(y). * Many classes are likely to have an "is-a" relationship to y, and I would like future developers to be able to provide their own implementations of fooTo, so I will choose y.fooTo(x). The latter two questions may not be as intuitive as the former, but I believe they are much more relevant if the goal of a design is to effectively manage complexity. Thoughts?