From: "Sean O'Dell" Date: 2003-09-04T02:43:22+09:00 Subject: Re: holub and OOP flavors Joe Cheng wrote: > 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. On these points, I wholeheartedly disagree. If x does the fooing, I presume that x is part of a level of abstraction already in-place. That is, if I can call 'printf(stderr, "something")', the I consider stderr to be part of an abstraction called "printing, but to an error stream". If stderr is part of a group of functions, all of which were developed BEFORE my OO program came along, then to prevent my program from a whole lot of non-OO code, I would wrap up stderr into an object. Therefore, that "* x.foo(y) is more natural because it's x that does the fooing" is, to me, almost exclusively the rule. We've also already talked a lot about the difference between string.print and device.print(string) and experience tells me that the most useful, re-usable pattern is device.print(string), which is a Real-World-imitating pattern. Therefore, the statement "* In the Real World, you don't tell a y to fooTo x, you just foo the y with x" is a darn good reason to organize objects a certain way. Also, regarding developer habits: I think experience teaches a person a whole lot that you can't get out of a book; most of that experience comes from "being there" and not "reading about it". So, if I know an excellent, excellent coder who shows me some code and can't articulate why it's a good way to do something, I don't reject his efforts on that basis alone. His experience tells me there's probably much more wisdom in the decisions he's made than anyone could reasonably articulate without spending a fair amount of time reflecting. Therefore, "* It just feels wrong, I don't know why" is often a perfectly valid reason. > 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). I find that "changing code" is not a criteria for design a set of classes, but often I *will* break code which is decidely transient into its own class so that unique implementations can be provided more easily. So, I agree more or less. > * 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). Organizing classes according to their abstractions (devices, strings, images, etc.), and by-task (printing, encrypting, etc.) will already show "is-a" relationships. I agree, you do have to design to allow developers to extend. You need to pick out your inheritance lines, keep methods using the lowest base class possible, etc. This is a finer point than was previously mentioned. There are other issues, too. But they don't override the basics: natural organization, encapsulate your abstractions. Unification of abstractions is another issue. Often you need to import code that is utterly, shockingly different from your projects design patterns. But I find that, if I stick to Real-World patterns and look for my inheritance lines, that's everything. If my code base is filled with classes that have natural relationships and are ordered into inheritance lines that minimize change from one level of inheritance to another, I find from there I can program just about anything I want, extend it later as much as I want, and I'm happy as a clam. > 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. Manging complexity is what it's all about. If you can get the complexity down far enough, there is no limit to what a project can acheive. Sean O'Dell