I'd add that modifying is worse than extending. If a library adds a method to an existing class, that's one thing. Sometimes it can be nice -- 1.day.ago is pretty cool! Does Rails use that stuff internally, or do you only get it if you ask for it? If you can't turn it off the main risk to adding methods is name collisions; someone else could add the same 'day' method to Number. Wasn't there a namespace feature of some sort proposed for Ruby 2 that would allow you to localize extensions? That would help. But swapping out method or constant definitions in standard libraries sounds really evil. If I read correctly, that was the real problem in the 'Chainsaw' message. (Great post.) Unless there's a name conflict with something else I use, I can live with something adding a method to a standard class. If I don't like that method I just won't use it. But if it changes the behavior of existing methods without even telling me, well that's just diabolical. Steve -----Original Message----- From: Austin Ziegler [mailto:halostatue / gmail.com] Sent: Wednesday, August 24, 2005 3:31 PM To: ruby-talk ML Subject: Extending Code Cleanly [NOTE: This is an offshoot of Zed Shaw's rant on Chainsaw Infanticide.] On 8/24/05, Jim Weirich <jim / weirichhouse.org> wrote: > Austin Ziegler said: >> On 8/24/05, Jeff Wood <jeff.darklight / gmail.com> wrote: >>> You shouldn't be afraid of having power. That's why you have tests. >>> You do have tests, right? ... right??? ... RIGHT !!?!?!?!??! >> I think the real problem is when this is done in released code. If >> you're going to extend code, extend it cleanly -- IMO. > Well said. > > It is probably worth having a public discussion on the meaning of > "extend cleanly". Aye, so I'll start. If you're going to extend core or standard library classes, you should: 1. Do so only at the user's request. Diff::LCS *can* extend String and Array but does not do so by default. If you are going to extend by default, then you must document it in a very loud tone of voice, as it were. 2. Don't depend on extensions to the core or standard library classes if you're working on a *library* of code for others to use. Subclass, extend (with a module), or delegate if you absolutely must. The predecessor to Diff::LCS (Algorithm::Diff) added #map_with_index or something similar to Array and depended on it. I don't think that Diff::LCS does that. Applications and application frameworks may have exemptions. This sort of allows for 1.day.ago notation as in Rails. 3. If you absolutely must extend the core and depend on it in a library, try to use names that don't interfere with others. Transaction::Simple follows #1, but it also follows this. -austin -- Austin Ziegler * halostatue / gmail.com * Alternate: austin / halostatue.ca