4 ms·
I think the argument here is to embrace the immutability of arrays in Ruby. The reason why this is called `reject!` rather than `reject` is because the designer
by tomphoolery 10y ago
I think the argument here is to embrace the immutability of arrays in Ruby. The reason why this is called `reject!` rather than `reject` is because the designers of Ruby wanted you to favor returning new objects rather than mutating objects in place. Sure, you might need to do it from time-to-time and I'm really happy we have methods that enable such behavior, but this brings to mind the old adage "just because you can, doesn't mean you should". The author might have been trying to say in that quote that app developers should find other ways of solving whatever problem they have without resorting to mutating objects in place. I don't think we should go as far as to not include such methods in Ruby if everyone finds them useful from time-to-time, but I also think we should be staying away from mutating objects in place, rather than returning new versions of said objects and using that.
- rickycook 10y agoi wouldn't have said that the ! is there because the designers want you to favour immutable rather than mutable operations. it's there for the same reason confirmations are there for deleting files; they want to you be sure you know what you're doing, because the immutable operation is always safe while the mutable operation is sometimes unsafe. if the ! for mutable operations weren't there, people would often be very surprised by the behaviour of reverse, sort, etc because in languages like ruby (python, etc too) they expect things to be fairly safe by default. there are plenty of cases when mutating an object is far preferable to doing the same in an immutable way for both speed, and algorithmic complexity.
- steveklabnik 10y agoSmall Ruby conventions note: ! means "dangerous", not "mutable." Yeah, sometimes the kind of danger you're looking at is mutability, but it's a bit broader than that.
- tamal 10y agoTo expand, ! means it's a more dangerous version of the method without the ![0]. A method could be dangerous, but not have a safer counterpart, and thus be named without a !. [0] https://www.ruby-forum.com/topic/176830#773946 https://www.ruby-forum.com/topic/176830#773946
- tyre 10y agoThat's not what the ! means. Matz has said a few times that this is not the case. "Bang" methods do not necessarily mean dangerous, just different.
- glitchdout 10y agoThat's actually the meaning Matz gives !. http://www.rubyletter.com/blog/2017/01/31/when-to-use-ruby-bang.html http://www.rubyletter.com/blog/2017/01/31/when-to-use-ruby-b...
- parenthephobia 10y agoIt's neither. It's reject! because reject already exists. Ruby isn't Scheme: a ! suffix doesn't have a simple conventional meaning. (Unlike a ? suffix.) The standard library has lots of side-effecting methods which don't come with ! suffix. On the same Array type that has reject!, there's delete, pop, push, among others. Only some of them have pure equivalents - e.g. last for pop.
- 8fGTBjZxBcHq 10y agoMethods in ruby only have the bang if there's another version of the method and this one might surprise you. Push and pop don't have it because they mutate the array like they do in almost every non-hardcore-functional language, so that's the expected behavior. Things like map! and reject! have them because there _is_ another version, and _this_ one might bite you. It has nothing to do with side-effects or immutability per se, that's just the most common case.
- smitherfield 10y agoMy impression is that the convention is a ! suffix means both that 1) There's another, similar, method without the suffix. 2) The ! version has some side effect (usually mutating something or throwing an exception) that the non-! doesn't, which doesn't mean that the non-! has no side effects (`ApplicationRecord#save` and `#save!` both have side effects, but only `#save!` throws on failure). — Is there any idiomatic Ruby library where ! methods don't follow this convention?
- smitherfield 10y agoImmutability by default is the right idea, but the nature of arrays as a data structure is that they are (should be) less expensive to transform in-place than by creating a copy. Mutation per se isn't harmful — if our ape brains were better able to think like a digital computer, we'd never have created functional programming (or even procedural, but I digress). What's harmful is our ape-brain habit to use mutation incorrectly (i.e. a buggy implementation). So a very large part of the problem can be solved with a (standard) library that provides (in theory) correct, performant implementations of common mutation patterns (such as Ruby's `Array#reject!`). (I realize you were taking the devil's advocate; I sort of am too, since I rarely use mutating methods when I write Ruby).