Behaviour of Array bang methods
The bang (!
) methods do modify the current object in place, but they do return nil
if there are no affected elements per the documentation. This is useful if, for whatever reason, you need to do something if you did modify the array in question.
if array.flatten!
puts "Oh yeah... flattened that array!"
end
Why Array#slice and Array#slice! behave differently?
#slice
and #slice!
behaviors are equivalent: both "return a subarray starting at the start index and continuing for length elements", the same way as #sort
and #sort!
return a sorted array or #reverse
and #reverse!
return a reversed array.
The difference is that the bang methods also modify the object itself.
a = [4,2,6,9,1,5,8]
b = a.dup
a.sort == b.sort! # => true
a == b # => false
b = a.dup
a.reverse == b.reverse! # => true
a == b # => false
b = a.dup
a.slice(2,2) == b.slice!(2,2) # => true
a == b # => false
Where to put exclamation mark when methods are chained
Exclamation marks are not modifiers.
array.reject!(&:blank?).map!(&:to_i).reject!{|i| i == 0}
However, this code is subtly wrong. From reject!
docs:
returns nil if no changes were made.
Whoops! This could break your whole chain. Instead, you're supposed to use delete_if, which always returns the array.
array.delete_if(&:blank?).map!(&:to_i).delete_if{|i| i == 0}
Yes, it's confusing it doesn't have a bang, but it does modify in-place. From the docs:
The array is changed instantly every time the block is called, not after the iteration is over.
.all?' method's strange behaviour
Because Enumerable#all?
says :
If the block is not given, Ruby adds an implicit block of { |obj| obj } which will cause all? to return true when none of the collection members are false or nil.
In your second line,the code return true
as none of the collection members are false
or nil
In your third line code returns true
,as all objects in your code collection (0,1) are true
,as in Ruby all objects are true
except nil
and false
.
In your first line,the code return false
,as the collection contains false
values along with true
values.
Shouldn't force_encoding be force_encoding! in ruby?
Contrary to popular belief, and many misleading beginners' ruby guides, bang methods do not mean "this method mutates the object".
That's usually the case, but not always.
A better interpretation of the convention for bang methods is "this is a more dangerous version of its non-bang counterpart".
For example:
String#gsub!
is the "dangerous" version ofString#gsub
, since it mutates the object.ActiveRecord::Base#save!
is the "dangerous" version ofActiveRecord::Base#save
, since it raises an exception if validation fails.exit!
is the "dangerous" version ofexit
, since the former exits immediately, whereas the latter actually raises an exception - which could be rescued elsewhere in the code.
Furthermore, note that there are plenty of ruby methods that do mutate the object but aren't bang methods. For example, String#delete
and Array#pop
.
This article goes into more detail on the matter.
So, (warning: opinionated response!) I would argue that:
- It's fine for
String#force_encoding
to be a non-bang method. This is not completely inconsistent with other conventions in the language. - If it were a bang method, it would require a non-bang counterpart for consistency.
- I, personally, don't think the use case for a non-mutating
String#force_encoding
is common enough to warrant its creation. In the rare case that you actually wanted to do this, you could write:string.dup.force_encoding(...)
.
.all?' method's strange behaviour
Because Enumerable#all?
says :
If the block is not given, Ruby adds an implicit block of { |obj| obj } which will cause all? to return true when none of the collection members are false or nil.
In your second line,the code return true
as none of the collection members are false
or nil
In your third line code returns true
,as all objects in your code collection (0,1) are true
,as in Ruby all objects are true
except nil
and false
.
In your first line,the code return false
,as the collection contains false
values along with true
values.
Ruby !sub returning strange null
It is documented that the sub! (like many of the ! string operations) return nil if no change was made.
From the docs
Performs the substitutions of String#sub in place, returning str, or nil if no substitutions were performed.
Instead use the regular sub. In your case the extra bang (!) is unnecessary.
'fafeafeafewafeawfeaw'.sub(/\.[^\.]*$/, '')
Bang Methods
The difference between sub
and sub!
is subtle. But in ruby in general, the non bang (!) version of a method is safer. Since by convention the bang means the method has more side affects.
In the case of string functions (and many array/enumerable functions) the bang means the method operates on the contents of the caller, instead of making (and returning) a copy.
s = 'fafafa'
puts s #=> 'fafafa'
puts s.sub(/fa/, 'fo') #=> 'fofofo'
puts s #=> 'fafafa'
puts s.sub!(/fa/, 'fo') #=> 'fofofo'
puts s #=> 'fofofo'
Kotlin spread operator behaviour on chars array
This happens because in Kotlin Array<Char>
is equal to Character[]
in Java, not to char[]
in Java.
To use the spread operator on an array of characters and pass it to a vararg Char
parameter, you need to use CharArray
which is equal to char[]
in Java.
fun main() {
val strings = arrayOf("one", "two")
val stringSplit = "".split("one", "two")
val stringsSplit = "".split(*strings)
val chars = charArrayOf('1', '2')
val charSplit = "".split('1', '2')
val charsSplit = "".split(*chars) // this is not possible
}
Related Topics
Writing Ruby Console Output to Text File
Get All Keys in Hash with Same Value
How to Prevent Rails Controller Generator to Modify Config/Routes.Rb
Ruby - Compare Two Enumerators Elegantly
What Are Fast Xml Parsers for Ruby
Rails Form Object with Reform-Rails with Collections Not Working or Validating
Ruby Net/Http Opening Connection Very Slow
Why Does Ruby Hash a Fixnum N to 2N+1
Creating a Gmail Draft with Recipients Through Gmail API
Parsing Command-Line Arguments as Wildcards
No Such File to Load -- Bundler/Setup (Ruby on Rails)
Ruby - What's the Difference Between Single and Double Quotes
Ruby Strftime '%Z' Method Returns '0545' Instead of 'Npt'