From: Trans Date: 2007-10-08T15:04:35+09:00 Subject: Re: The Case for Multiple-Inheritance On Oct 7, 8:45 pm, "Austin Ziegler" wrote: > On 10/7/07, Trans wrote: > > > On Oct 7, 8:42 am, "Austin Ziegler" wrote: > >> No, actually, it doesn't provide maximum code reusability. Ruby > >> supports a rich vocabulary and you're choosing to use a form that, > >> while clearly useful in some cases, is not right. > > Yes it does, b/c if methods are placed in a class, the only reuse if > > via a subclass. > > You are 100% wrong here. Not all reuse is defined by mixin or > inheritance. Delegation and composition are also reuse. Fair enough, although that's only 50% wrong ;) But the point was the restriction of having to pick one construct (class vs. module) over the other. A module can *almost* do anything a class can. One can even effectively initialize a method via Class.new{ include Mod }. Of course this is less convenient and one must fuss with ClassMethods and be careful of the Double Inclusion Problem, but my point clearly stands: modules are more versatile than classes. Thus by using all modules for behavior (and classes as only compositions of modules) maximizes reusability. And for this simple fact: classes cannot be mixed-in. > > If they are in a module they are not limited by that constraint. I > > haven't lost anything at all by putting all behavior in modules, I > > have only gained. The approach is a superset. > > The approach is a mess and tries to abstract things out in a nonsensical > way. Essentially, you're saying that UP FRONT you divide things into one > or more "class modules" and one or more "instance modules". With few > exceptions, modules should be extracted from classes when you can think > of a more-generic case for it. And you don't extract the whole damned > class to pull it off; you pull the special-purpose-for-similar-objects > code out. Huh? It's a mess to divide these things into modules for mixin, but its ok to divide them as classes and delegate? The point is to make less mess by dividing things up into more manageable pieces. Those pieces may prove nicely reusable, too, if well thought out, btw. But my example of extraction of the *whole* damned class was to make a point about the limitations of class vs module reuse. For instance, here's an example I didn't mention before. Did you know that if you use all modules then AOP coding is very simple? It's easy to prepend a module relative to other modules in the inheritance chain. But not so for classes. Dynamic AOP for classes takes some mind-numbing meta- coding for sure. > > I seem to be the only one who ever gives code examples. How about you > > show me an example of how you'd do it? > > You've got plenty of examples of how I'd do it: it's called my existing > Ruby code that's out there publicly on RubyForge. (This is probably > close to ten thousand lines of code ... that doesn't do what you're > talking about except in one instance I can think of that I only did it > that way for clarity and wouldn't do it that way again.) Of course I've seen some of your code, Austin. And you're quite a capable coder. But your Ruby code has a very classic feel to it. Like you were programming in C. You're very conservative and don't much venture into the meta-coding deep. I'm not insinuating anything negative in that, btw. I think it's good that there are all types of coders. But you seem almost religious about your way of doing things. > I mostly do it as classes. I don't screw around with modularizing things > that simply *aren't* modules. Just because you CAN extract all of the > purpose out of a class and put it into a module just to include it right > back in doesn't mean you SHOULD. Of course not. And of course I don't. But I wish Ruby didn't make me have to choice one over the other. It reduces the flexibility of it's otherwise extremely elegant inheritance model; and likewise makes delegation the better choice in more cases than otherwise would be necessary. > >> Modules in Ruby are useful for adding new "generic" class > >> capabilities. > > >> Enumerable is a way of using the ability to iterate over a collection > >> object (and a collection is defined by #each, which goes through the > >> *state values* of the object in turn). It's like a Java interface > >> except that you don't need to reimplement each and every piece of the > >> interface because the interface is always expressed in terms of > >> #each. > > >> Transaction::Simple is a way of adding "extra" state to an object > >> that allows it to be versioned in memory. All of that extra state is > >> managed by the methods defined in the module. > > >> What you're talking about is on par with components and graphical > >> development. They can work in simple cases, but the moment you start > >> having complex cases, you start realizing that the code is becoming a > >> bit more complex to integrate that way. You can either refactor your > >> code, or start looking at ways that the language can change to > >> accomodate your model's inflexibility. > > >> Modules aren't really meant for providing state that the object > >> depends on normally. They're *extra*. So you should be working with > >> classes that have implementations; you should re-factor out common > >> functionality (and I mean REALLY common functionality) into modules; > >> you should have a class hierarchy if it's appropriate; you should > >> compose multiple objects into a single object where appropriate. > > You are constraining the use of modules according to your own view of > > how they "should" be used, and in the process I think you're missing > > my point. > > No, I didn't miss your point at all. I think your approach is stupid and > shortsighted. Sorry for the harshness, but the reality is that using > modules this way is nonsense and you're running into limitations because > you're trying to do something that doesn't make sense. I'm not saying > that Ruby's perfect or that everything in it makes sense, but if it > *hurts* to do something one way in Ruby, that's usually a sign that > you're doing it wrong. Ah yea, and "If God meant for men to fly, he would have given them wings." You're arguing that I have the problem, not Ruby. But I'm not arguing Ruby has a problem, I'm arguing that maybe it could be even better. Nor do I have a problem. I finished the program yesterday. I didn' run into a limitation per-se, I ran in to a "why am I having to make an ultimately pointless distinction?" > > You've created an artificial separation between forms of code > > encapsulation because, you reason to yourself, one is for handling > > state and one if for generic capabilities. > > It's not artificial. In Ruby, modules do not contain state. Period. Only > objects, which are instances of classes, contain state. Now you're knit picking words. Of course only object instances have state. But classes, and modules!, define objects. > The canonical > examples of modules (Enumerable, Comparable) don't deal with state > directly, but only through a defined interface that DOES deal with state > in an object. Transaction::Simple is a module because it adds functions > to objects that allow those objects to manipulate state in different > ways. > > Transaction::Simple has generic applicability. Text::Format does not. Yep. A well defined interface is an important aspect of code reuse -- that's true for all forms of composition. > > But that is putting a hard line in a soft world. There really is no > > need to make that hard distinction. If a coder, like yourself, wants > > to do that you can do so just as easily with a single form of > > encapsulation.... > > [snip the rest of this nonsensical paragraph and the entire next > paragraph that has nothing to do with what I said] > > Do NOT try to put words in my mouth. What words? You always do this Austin. You makes some admonishing remark and then never explain what your talking about. It's a very deceptive conversational tactic. And I wish you'd cut it out. Explain yourself. What words do you mean? What I have I said that is nonsensical? And why do you think it's all in reference to what you said. What about the point *I* trying to make? > >> I'll put it clearly: if I were running a Ruby consultancy and a > >> programmer of mine used your methodology for everything (e.g., > >> classes defined by composing modules), I would not keep that > >> programmer on. It's a bad style. Sorry. > > Clearly there is a reason you aren't running a consultancy. > > ...which has nothing to do with this stance. You write bad code and > design badly. You always want to change the language to fix the fact > that you've coded yourself into a corner. You've done this for years, > Trans. No. For years I have explored the language. Pushed up against it's boundaries. Investigate what it can and can't do. I bring up ideas and make suggestions to explore those further, not because I'm stuck, but because I'm curious. I'm forever learning. I didn't come from a C background and just started writing my C program's in Ruby. I learned Ruby as Ruby. And I try to use Ruby for what it is, and enjoy considering what more it could be. Does this exploration lead me down rough roads sometimes? Damn right it does. But in the end I'm a better coder for it. Am I the best coder around here? Of course not, I don't pretend to be. But you sure do. > Classes defined by composing modules is bad practice. There are times > for doing things like this, but they are few and far between and people > who do it should be prepared to defend their reasons for doing so > because it smells like bad code. Good gracious. You have so utterly missed the whole point I'm not sure why I continue to type. What was my point Austin? Please, I want you to put words in my mouth so I can see if there's actually any communication going on here. T.