From: Michael Neumann Date: 2001-09-04T07:48:20+09:00 Subject: [ruby-talk:20821] Re: RCR: non-bang equivalent to []= Tobias Reif wrote: > Matz, > > > > |I'd like to have bang and non-bang versions of each and every method. > > |The names should just differ in the !, like collect and collect! > > > > Like scheme? But imagine that every destructive (in other words, self > > modifying) method has ! in its name, Ruby programs would be filled > > with bangs. It might be informative, but let's face it, it's ugly. > > > By reading the docs, everyone can find out how each method acts. > But a stringent concept would help programmers to always know how a > method behaves in this aspect; which would benefit the Princple of Least > Surprise. > > If we were in the early phase (not having to consider finalized > decisions, and backwards-compatibility): > > If destructive methods are more often used that non-destructive one, the > "default" (shorter name) could be destructive. > Otherwise, the default is to be non-destructive, like now. > > I agree that '!'s all over the place could be ugly. > So maybe: > All methods are destructive by default, and every method has a > counterpart which is non-destructive; since it returns a copy, _c could > be appended (exact naming convention is just a detail of a stringent > concept.). > > Ruby is already at 1.7.x, so it's too late for all this. > Or is it? > Conventions for writing publicly available Ruby methods are interesting. > And Ruby 2 too. > > Here are more thoughts: > > > I'm currently learning Ruby, and I like it a lot. > > At first I thought that all methods return modified copies, > and only "!" methods modify the original. > > Then I ran into many problems, because []= > is bang without having a "!" appended, and doesn't have > a non-bang version. > > AFAIK, there are many more methods that are destructive but don't > declare that in their name: > clear, delete, delete_at, delete_if, fill, pop, push, replace, shift, > unshift, Array#filter. "!" tells you "it's more dangerous to use it than the non-bang method". I don't thinks it's good to have for each method both, a destructive and non-destructive version. There is no Array#delete!, because it's obvious that delete is destructive; for the non-destructive version you might use Array#reject. > It would be OK if all methods are bang by default, and have some > version which is non-bang. I don't like that. How to name the non-bang methods? Changing this would break all Ruby code out there. > But I think any stringent concept and naming convention not only > would immensely help beginners, > but add to Ruby's semantic richness and clarity. > Something like > "Beware, however, that there are a fair number of destructive methods > that don't have an '!' " > in the FAQs it not a nice discovery for everyone learning Ruby. Once again, "!" only marks a method as dangerous, that do not means, others without it are less dangerous (destructive). For me it's obvious that a.delete_if {|i| i > 2} would delete all elements larger than 2 from Array a. As mentioned above, I'd write b = a.reject {|i| i > 2} for the non-destructive counterpart. For me, this is PoLS. If a method has a "!" version, you exactly know what each does. If there is no "!" version then take a look at the method name, if it sounds destructive (delete, set []=, push, pop) then the method is destructive. > "The plain version takes a copy of the receiver, makes its change to it, > and returns the copy. The version with the ! modifies the receiver in > place." > is a rule with many non-obvious exceptions. > This fact which generates confusion, and sabotages the > "Princple of Least Surprise" in a very relevant way. > > Any concept would solve the problem, as long as it's 100% stringent. This would be the "Principle of No Surprise" but not PoLS ;-) > (it could also be promoted as good style for all Ruby programs and libraries > that make methods available. For example: > Every method without a '!' makes a copy, > every method with a '!' is destructive. > Every method that is to be used by others > (in public classes, libraries, etc.) should consist of both versions.) There are many methods, that do not modify the object; should then for each method a "!" version? There are two many methods, where this doesn't make any sense (most libraries other than datatypes). class Sensor def getTemparature @temperature end def setTemparature(x) @temperature = x end end Method "setTemperature" is destuctive, should it return a modified copy? Or would you call "setTemperature!" instead ? Would you use Array#pop! instead of Array#pop? > One possible concept: > > (current, and stringent) > 1. Variable assignment ist just that; nothing gets copied. > 1.1. Use dup or clone to get a copy, and assign that. > > (possible:) > 2. Every method returns a (possibly modified) copy of what it > worked with. > 2.2. Every method has a version that doesn't make a copy, > but directly works with the original. > > Or: > (possible:) > 2. Every method works directly with the original. > 2.2. If you don't want to modify the original, > use dup or clone to get a copy and pass that. > > Naming conventions like: > map, copy_and_map > or > map_original, map > or even > map_original, copy_and_map > are semantically rich, but too long. > > So perhaps: > map, map! I am sure, the longer you work with Ruby the more you'll like the method names as they are. Regards, Michael -- Michael Neumann merlin.zwo InfoDesign GmbH http://www.merlin-zwo.de