I'm a newbie to Ruby, and so far have found the explanations for ! a bit too technical.
Let's say we have the following:
print "What is your first name?"
first_name = gets.chomp.upcase!
puts "Hi, #{first_name}. How are you?"
What does the ! add to the method? Does it mean that every time I use #{first_name} in any subsequent strings, all the letters in the name will print in upper-case? How is the code affected if I leave ! out?
Please explain it in layman's terms if you can, as I'm still coming to grips with some of Ruby's technical jargon.
Thanks in advance.
Ruby method names may end in !. It doesn't do anything special by itself, but there is a convention on which methods have it (though it is not always consistent); thus, just learn the method String#upcase! (and how it differs from String#upcase) on individual method-by-method basis, with the convention being a helpful reminder.
The convention is that the methods ending in ! are either dangerous, or change the object, or perform some other kind of change, or can raise an error where the other version wouldn't.
Specifically, String#upcase! changes the string it operates on. String#upcase makes a new string that is upcased.
foo = "test"
p(foo.upcase) # => "TEST"
p(foo) # => "test"
foo = "test"
p(foo.upcase!) # => "TEST"
p(foo) # => "TEST"
As described in comments, String#upcase! returns nil when no upcasing needs to happen, so you never want to reassign the return value of String#upcase! back to the same variable you tried to upcase!.
foo = "TEST"
p(foo.upcase!) # => nil
p(foo) # => "TEST"
RE: bang methods: see here
EDIT: "receiver" is the object receiving the message (i.e. method call). In foo.upcase!, the object in foo is the receiver. In "TEST".upcase, the string "TEST" is the receiver.
"in-place"` means the object itself is changed. The alternative is to create a new object that has the changes you want applied, with no change to the original object. For example, if you have a photo, cover the bottom half with a piece of paper and take a photo of that, you did a crude censorship by creating a new photo that is missing the lower half (but the original still exists). If you splat paint on the original photo, you censored it "in place".
What does the ! add to the method?
Nothing. The ! is simply part of the message name, just like the u, the p, the c, the a, the s, and the e are. It does not change anything about the message.
How is the code affected if I leave ! out?
Then you are simply sending a different message.
There is absolutely no difference whatsoever between upcase and upcase! or between foo and bar. They are just message names. If you write foo, then you send message foo, if you write bar, then you send message bar, if you write upcase, then you send message upcase (which in your case will be dispatched to the method String#upcase), if you write upcase!, then you send message upcase! (which in your case will be dispatched to the method String#upcase!).
There is absolutely nothing special about message names ending in !, just like there is absolutely nothing special about message names ending in ?, just like there is absolutely nothing special about message names ending in a or b or c.
There are, however, some conventions. In particular, the convention is:
If you have a pair of methods that both do more or less the same thing, then the one that is more surprising is named with a !.
That's it. That is all there is to it.
For example, there are the methods Process::exit and Process::exit!. They both do the same thing (terminate the process), but one of them skips running the installed exit handlers.
Since they both do the same thing, they could both be named "exit", but of course, you can't have two methods with the same name (on the same receiver). Therefore, we need to somehow distinguish between the two. We could come up with a completely different name for one of the two, but that would also be annoying.
So, instead, we add a ! to one of the two methods. Now, the question is: which one of the two do we add the ! to? Based on our convention, the "more surprising" one should get the !. The Ruby developers chose the one which ignores the exit handlers, which I think is the right choice: the whole point of exit handlers is that they get run when you exit, so a method that exits without running the exit handlers is surprising, and therefore should be marked with a !.
Note that none of this has anything to do with "destructive" or "mutation". Process::exit! doesn't mutate anything and it doesn't destroy anything. Note also that we only use the ! to mark the more surprising method of a pair of methods. There should never be a method named foo! when there is not also a method named foo.
In particular, the fact that a method does not have a ! does not tell you anything about the method. And the only thing that a method that does have a ! tells you is that there are two methods, and you should probably check the documentation to make sure that you understand what these two methods do and what the "surprise" is that the ! is warning you about. That's it.
Related
I'm analyzing a block of code written in ruby.
I don't know the language and I need to understand an operation.
def restore
m = ObjectName.where(prop: User.where(email: 'admin#email.com').first.element_id).last
m.todo!
m.waiting!
...
end
what "m.todo!" and "m.waiting!" are doing?
I cannot understand if it is assigning a "true" value or a value that is the opposite of the current one like: m.todo = !m.todo
Thank you very much
! and ? are valid parts of a method name in Ruby. They don't have any special meaning, though ! is conventionally used for mutative or destructive actions, and ? is conventionally used for predicate methods.
In this example, there are two methods named todo! and waiting! being called - nothing fancier. If I had to guess, those are methods which simply perform a combined "update a state variable and save" operation (hence, mutative).
In Ruby, foo.bar is the syntax for a message send. It will first evaluate the expression foo (which is either dereferencing a local variable or a receiverless message send to the implicit receiver self) and then send the message bar to the resulting object.
Once you know what message send in Ruby looks like, it is easy to see what m.todo! does: It will first evaluate the expression m (which is either dereferencing a local variable or a receiverless message send to the implicit receiver self) and then send the message todo! to the resulting object.
Method names ending in ! are typically used to mark the "more surprising" of a pair of methods. So, if you have two Methods, both of which do similar things, then the one with the bang at the end is the "more surprising" one. A good example are Process::exit and Process::exit!. Both exit the currently running Ruby process, but the "normal" version (i.e. the one without the bang) runs the exit handlers normally, whereas the "surprising" Version exits immediately without running the exit handlers.
Note: there seems to be a lot of misunderstanding About the naming convention for bang methods. So, let me be clear:
Bang methods have absolutely nothing to do with mutation or destruction. It is simply about surprise. See the Process::exit! example above which has nothing to do with mutation.
Bang methods are always paired with a non-bang method. They mark the "more surprising" variant of a pair of methods. If there is no pair of methods, there is no bang. See, for example Array#collect!, which does have a bang because it is the more surprising variant of Array#collect, since it mutates its receiver; however, Array#append does not have a bang even though it also mutates its receiver because there is no corresponding "less surprising" method.
what "m.todo!" and "m.waiting!" are doing? I cannot understand if it is assigning a "true" value or a value that is the opposite of the current one like: m.todo = !m.todo
They do whatever the author of those methods wants. You will have to look that up in the documentation. Those are not methods of the Ruby core or standard library.
For example, I've checked the documentation on certain methods, like sort. And it looks like the only difference between .sort and .sort! is that one sorts self in place and the other returns an array. I'm a little unclear on what that means - they seem to effectively do the same thing.
Can anyone help me understand this a little better?
When to Use Bang Methods
Technically, the exclamation point (or bang) doesn't intrinsically mean anything. It's simply an allowable character in the method name. In practice, however, so-called bang methods generally:
Changed objects in-place. For example, #sort! sorts self in place, while #sort returns a new array created by sorting self.
Some bang methods return nil if no changes were made, which can cause problems with method chains. For example:
'foo'.sub 'x', 'y'
# => "foo"
'foo'.sub! 'x', 'y'
#=> nil
Use bang methods when you want to mark a method as creating notable side effects, producing destructive operations, or otherwise requiring additional caution or attention. This is largely by convention, though, and you could make all your methods bang methods if you were so inclined.
Methods with a bang(!) are meant to signify a little more caution is required. So, either modification in place vs. not in place (if you are modifying the object in place - you better be sure that you really want to), or in other cases like find_by and find_by! (see here) where one causes an exception if no record is found and one doesn't cause an exception.
Can you guess which one does and which one does not cause an exception?
The methods with the exclamation point alter the actual object they're called on, where as the methods without will just return a new object that has been manipulated.
i.e.
pizza = 'pepperoni'
pizza.capitalize
Now the pizza variable will still equal 'pepperoni'.
If we then call
pizza.capitalize!
The pizza variable will now equal 'Pepperoni'
"Inches/yard: #{12*3}"
"#{"Tora! "*3}"
The second example is confusing, unless you remember that everything is an object in
Ruby (yes, even string literals! They are of class String.). Since the string literal
creates a String object, you can act on it just like any other object. In this case,
multiplying a string by 3 simply does what you would think: makes three copies of the
string.
I read the above para in one of the ruby book. The first line says The second example is confusing, unless you remember that everything is an object in Ruby. What is there in the second example that i should remember ,everything is an object in ruby ? Isn't it just a feature that multiplying by 3 will print tora three times ?
I don't exactly understand what does the author want me to understand from the above paragraph
Well, yes you can consider it a feature maybe, but what the author is perhaps trying to explain (although not very clearly at least in this one paragraph), is that what actually is happening is this:
"Tora !" is an object of class String ("everything is an object")
"you can act on it just like any other object", meaning:
"you can call any method on it just like any other object".
In this case you are calling the method * (multiply).
So what ACTUALLY is happening is that the "Tora !" String gets called in a fashion like this:
"Tora ! ".*(3)
=> "Tora ! Tora ! Tora ! "
You see? The operator * is just a method on the String object.
In many simpler languages operators are actually "baked into" the language itself, and do not operate on the targets as method calls.
If you're not used to other languages you might not find it all that remarkable, since in Ruby it's just a normal everyday thing. You just never need to type 1.+(2), Ruby does it for you automatically when you type 1 + 2.
So this is what the author wants you to remember - all operators and operations are just essentially method calls on other objects.
"Tora! a" is an instance of the String class. You can call methods on it. This isn't possible in many languages, e.g. PHP.
('*' is just the method name)
"#{"Tora! "*3}"
"Isn't it just a feature that multiplying by 3 will print tora three times ?".
That is inexact. There is no such thing as a multiplying operator in Ruby. There is a method ".*" (and the parser treats "*" the same way) defined on both String and Numeric objects (but both don't print anything). They do very different things, but the result is what you'd expect.
Well, maybe this was not what the author wanted you to understand, it is important anyway.
Sometimes I see methods in Ruby that have "?" and "!" at the end of them, e.g:
name = "sample_string"
name.reverse
name.reverse!
name.is_binary_data?
I was wondering what their purpose is? Are they just syntax sugarcoating?
It's "just sugarcoating" for readability, but they do have common meanings:
Methods ending in ! perform some permanent or potentially dangerous change; for example:
Enumerable#sort returns a sorted version of the object while Enumerable#sort! sorts it in place.
In Rails, ActiveRecord::Base#save returns false if saving failed, while ActiveRecord::Base#save! raises an exception.
Kernel::exit causes a script to exit, while Kernel::exit! does so immediately, bypassing any exit handlers.
Methods ending in ? return a boolean, which makes the code flow even more intuitively like a sentence — if number.zero? reads like "if the number is zero", but if number.zero just looks weird.
In your example, name.reverse evaluates to a reversed string, but only after the name.reverse! line does the name variable actually contain the reversed name. name.is_binary_data? looks like "is name binary data?".
Question mark indicates that the method returns boolean. Already answered here:
What does the question mark operator mean in Ruby?
The bang indicates that the method acts on the object itself. Already answered here:
Why are exclamation marks used in Ruby methods?
In Ruby the ? means that the method is going to return a boolean and the ! modifies the object it was called on. They are there to improve readability when looking at the code.
In contrast to the – I suppose – majority of programming languages ...
Ruby, methods are allowed to end with question marks or exclamation marks.
By convention, methods that answer questions (i.e. Array#empty? returns true if the receiver is empty) end in question marks.
Potentially “dangerous” methods (ie methods that modify self or the arguments, exit! etc.) by convention end with exclamation marks.
From: http://www.ruby-lang.org/en/documentation/ruby-from-other-languages/, Section Funny method names
Beware, this isn't always the case. Take for example, Ruby Array#concat http://docs.ruby-lang.org/en/2.0.0/Array.html#method-i-concat.
Where you can get burnt badly is something like MyActiveRecordModel.column_names.concat([url]). Later calls related to MyActiveRecordModel will try to look for a column of 'url' for MyActiveRecordModel and throw.
Instead you must clone it before doing the concat. Fortunately my test suite caught this one, but.. heads up!
In Ruby some methods have a question mark (?) that ask a question like include? that ask if the object in question is included, this then returns a true/false.
But why do some methods have exclamation marks (!) where others don't?
What does it mean?
In general, methods that end in ! indicate that the method will modify the object it's called on. Ruby calls these as "dangerous methods" because they change state that someone else might have a reference to. Here's a simple example for strings:
foo = "A STRING" # a string called foo
foo.downcase! # modifies foo itself
puts foo # prints modified foo
This will output:
a string
In the standard libraries, there are a lot of places you'll see pairs of similarly named methods, one with the ! and one without. The ones without are called "safe methods", and they return a copy of the original with changes applied to the copy, with the callee unchanged. Here's the same example without the !:
foo = "A STRING" # a string called foo
bar = foo.downcase # doesn't modify foo; returns a modified string
puts foo # prints unchanged foo
puts bar # prints newly created bar
This outputs:
A STRING
a string
Keep in mind this is just a convention, but a lot of Ruby classes follow it. It also helps you keep track of what's getting modified in your code.
The exclamation point means many things, and sometimes you can't tell a lot from it other than "this is dangerous, be careful".
As others have said, in standard methods it's often used to indicate a method that causes an object to mutate itself, but not always. Note that many standard methods change their receiver and don't have an exclamation point (pop, shift, clear), and some methods with exclamation points don't change their receiver (exit!). See this article for example.
Other libraries may use it differently. In Rails an exclamation point often means that the method will throw an exception on failure rather than failing silently.
It's a naming convention but many people use it in subtly different ways. In your own code a good rule of thumbs is to use it whenever a method is doing something "dangerous", especially when two methods with the same name exist and one of them is more "dangerous" than the other. "Dangerous" can mean nearly anything though.
This naming convention is lifted from Scheme.
1.3.5 Naming conventions
By convention, the names of procedures
that always return a boolean value
usually end in ``?''. Such procedures
are called predicates.
By convention, the names of procedures
that store values into previously
allocated locations (see section 3.4)
usually end in ``!''. Such procedures
are called mutation procedures. By
convention, the value returned by a
mutation procedure is unspecified.
! typically means that the method acts upon the object instead of returning a result. From the book Programming Ruby:
Methods that are "dangerous," or modify the receiver, might be named with a trailing "!".
It is most accurate to say that methods with a Bang! are the more dangerous or surprising version. There are many methods that mutate without a Bang such as .destroy and in general methods only have bangs where a safer alternative exists in the core lib.
For instance, on Array we have .compact and .compact!, both methods mutate the array, but .compact! returns nil instead of self if there are no nil's in the array, which is more surprising than just returning self.
The only non-mutating method I've found with a bang is Kernel's .exit! which is more surprising than .exit because you cannot catch SystemExit while the process is closing.
Rails and ActiveRecord continues this trend in that it uses bang for more 'surprising' effects like .create! which raises errors on failure.
From themomorohoax.com:
A bang can used in the below ways, in order of my personal preference.
An active record method raises an error if the method does not do
what it says it will.
An active record method saves the record or a method saves an
object (e.g. strip!)
A method does something “extra”, like posts to someplace, or does
some action.
The point is: only use a bang when you’ve really thought about whether
it’s necessary, to save other developers the annoyance of having to
check why you are using a bang.
The bang provides two cues to other developers.
that it’s not necessary to save the object after calling the
method.
when you call the method, the db is going to be changed.
Simple explanation:
foo = "BEST DAY EVER" #assign a string to variable foo.
=> foo.downcase #call method downcase, this is without any exclamation.
"best day ever" #returns the result in downcase, but no change in value of foo.
=> foo #call the variable foo now.
"BEST DAY EVER" #variable is unchanged.
=> foo.downcase! #call destructive version.
=> foo #call the variable foo now.
"best day ever" #variable has been mutated in place.
But if you ever called a method downcase! in the explanation above, foo would change to downcase permanently. downcase! would not return a new string object but replace the string in place, totally changing the foo to downcase.
I suggest you don't use downcase! unless it is totally necessary.
!
I like to think of this as an explosive change that destroys all that has gone before it. Bang or exclamation mark means that you are making a permanent saved change in your code.
If you use for example Ruby's method for global substitutiongsub!the substitution you make is permanent.
Another way you can imagine it, is opening a text file and doing find and replace, followed by saving. ! does the same in your code.
Another useful reminder if you come from the bash world is sed -i has this similar effect of making permanent saved change.
Bottom line: ! methods just change the value of the object they are called upon, whereas a method without ! returns a manipulated value without writing over the object the method was called upon.
Only use ! if you do not plan on needing the original value stored at the variable you called the method on.
I prefer to do something like:
foo = "word"
bar = foo.capitalize
puts bar
OR
foo = "word"
puts foo.capitalize
Instead of
foo = "word"
foo.capitalize!
puts foo
Just in case I would like to access the original value again.
Called "Destructive Methods" They tend to change the original copy of the object you are referring to.
numbers=[1,0,10,5,8]
numbers.collect{|n| puts n*2} # would multiply each number by two
numbers #returns the same original copy
numbers.collect!{|n| puts n*2} # would multiply each number by two and destructs the original copy from the array
numbers # returns [nil,nil,nil,nil,nil]
My answer explains the significance of Ruby methods with exclamation marks/shebangs in the context of Ruby on Rails (RoR) model validations.
Essentially, whenever developers define Model validations (explained here), their ultimate goal is to decline a database record change & raise/throw the relevant exception(s) in case invalid data has been submitted to update the record in question.
RoR ActiveRecord gem defines various model manipulation methods (Ruby on Rails guides.). Among the methods, the valid? method is the only one that triggers validation without database action/modification. The rest of the methods attempt to change the database.
These methods trigger callbacks whenever they run. Some of the methods in the list feature a sister method with a shebang. What is the difference between the two? It has to do with the form of callback returned whenever a record validation fails.
Methods without the exclamation/shebang merely return a boolean false in the event of record validation failure while the methods with a shebang raise/throw an exception which can then be handled appropriately in code.
Just as a heads-up, since I experienced this myself.
In Ruby, ! mutates the object and returns it. Otherwise it will return nil.
So, if you are doing some kind of operations on an array for example, and call the method .compact! and there is nothig to compact, it will return nil.
Example:
arr = [1, 2, 3, nil]
arr.compact!
=> [1, 2, 3]
Run again arr.compact!
=> nil
It is better to explicitly return again the array arr if you need to use it down the line, otherwise you will get the nil value.
Example:
arr = [1, 2, 3]
arr.compact! => nil
arr # to get the value of the array