Why is a space allowed between minus and a number? - ruby

These are expected:
-3 # => -3
0 - 3 # => -3
But what is happening here:
- 3 # => -3
My first thoughts was - is a method on the implied self, i.e. self.-(3), so defined on Kernel or Object. But trying this results in NoMethodError: undefined method.

Ruby has a pretty forgiving syntax and allows things like this. That's parsed as a unary minus operator. It negates whatever's on the right hand side.
Also similar:
-(3)
# => -3
-(-(-3))
# => -3
- (3)
# => -3
It's similar to how you can omit braces on method calls: foo x is valid, but foo(x) is implied. You can also do foo (x) though that can lead to ambiguity so it's generally frowned upon.
As Dave Newton points out, internally this is actually:
3.send(:-#)

Related

How to understand objects, methods and arguments in Ruby calculations

While learning Ruby gotchas, I am getting different results with some calculations in IRB:
1-2-7-2 # => -10
1.-2.-7.-2 # => 4
1.-2.-7.-2.-4 # => 8
1.-2.-7.-2.+4 # => 0
1.-(2).-(7).-(2) # => -10
Possibly it is related to methods and arguments? I am trying to wrap my head around this.
You've chosen an interesting way to approach calculations.
I guess you are trying to omit zeros in your expression 1.-2.-7.-2 which will return -10 if you write it as 1.0 - 2.0 - 7.0 - 2.
The way you're getting 4 is because 1.- construction calls -() method because everything is an object in Ruby and then you pass an argument to the function.
In your case it will be parsed as
1.-( 2.-( 7.-(2) ) )
# if we try to unwrap
a = 7.-(2) # => 5
b = 2.-(a) # => -3
1.-(-3) # (or 1 + 3) => 4

How important is whitespace inside parens in Ruby?

I just discovered that whitespace inside parens can matter in Ruby in an unexpected way:
Here are 3 functions which look semantically identical to me:
def foo(x)
return {
:a => (x - 100),
}
end
def bar(x)
return {
:a => (x
- 100),
}
end
def zot(x)
return {
:a => (x -
100),
}
end
However, foo(10) and zot(10) return {:a=>-90} (as I expected) while bar(10) returns {:a=>-100} (to my dismay and disappointment).
What am I missing here?
It's an unusual case here but I believe what you're seeing is Ruby interpreting that as several consecutive statements and not a single statement. As in it sees that as:
x # Statement 1
-100 # Statement 2
Where the result of that block of code is -100.
In the case of zot you've expressed your intent to continue that line on the next by having a dangling - binary operator:
x - # Statement 1
100 # Statement 1 (cont)
It's worth noting that you can't do this when making method calls:
zot(x
-100 # Syntax error
)
As in that case the argument syntax rules are a lot more strict. Inside a free-form (...) structure you have considerably more latitude.
In Ruby, there are two possible expression separators: semicolon ; and newline.
So,
a
b
is the same as
a; b
Which means that
a
- b
is the same as
a; - b
which is the same as
a; b.-#()
Of course, you expected it to be equivalent to
a - b
which is the same as
a.-(b)
The point is: each of those two interpretations is equally valid. The language designer has to choose one of those two interpretations, and in this case, they chose the first one. Neither of the two is more "right" or more "correct".
If they had chosen the second interpretation, then you wouldn't have asked this question, but someone else would have asked the opposite one.

What does the bracket operator do to a FixNum in Ruby?

Coming from Python I find the following behaviour very surprising:
irb(main):211:0> x= 33
=> 33
irb(main):212:0> x[0]
=> 1
irb(main):213:0> x[1]
=> 0
irb(main):214:0> x[2]
=> 0
Is there a rationale/philosophy for not raising an error in this example?
The bracket operator gives you the nth bit of the binary representation:
http://ruby-doc.org/core-2.1.2/Fixnum.html#method-i-5B-5D
You might be a little confused about what this is doing internally, but that's normal when dealing with Ruby because it's quite unlike other scripting languages. Unless you've used SmallTalk it might even seem insane.
When Ruby sees the following code:
x = 6
x[1]
What it's actually doing is this:
x.send(:[], 6) # Send :[] method call to x with arguments [ 6 ]
The x object is free to interpret that however it wants, and the behaviour is typically (though not always) defined by the class x belongs to if x is a normal instance.
In this case it's returning the bit at a given index, equivalent to x & (1 << 6) >> 6.
Sometimes the [] method does several things:
string = "brackets"
# Retrieve a single character
string[1]
# => "r"
# Retrieve a substring
string[5,2]
# => "et"
# Perform a pattern match
string[/[^aeiou]+/]
# => "br"
This also does some pretty crazy things since you can apply it to a Proc as well:
fn = lambda { |x| x + 1 }
# Conventional (explicit) call
fn.call(2)
# => 3
# Square bracket method
fn[5]
# => 6
Since Ruby leans very heavily on Duck Typing, this means that you can write a Proc to fill in where you'd normally have a Hash or an Array and the method receiving your object is none the wiser.
It's this flexibility in leaving the meaning of x[...] for your own class instance x up to you that makes it pretty powerful.
For example:
class Bracketeer
def [](i)
"%d brackets" % i
end
end
bracketeer = Bracketeer.new
bracketeer[6]
# => "6 brackets"
This simple notation often comes in handy when you're trying to create a minimal interface for a class of yours. In many cases you can use something simple like [] to replace what would be a more verbose method like find_by_id or cache_fetch.
Certainly. You'll find that the manual is quite illuminating.
This is returning the binary bit for the bit position value as a zero or one.
It is returning the n'th bit as rightfully observed by #msergeant.
What this means is, for the number 33, its binary representation is:
Index : [7][6][5][4] [3][2][1][0]
Bits : 0 0 1 0 0 0 0 1
Which explains the output:
irb(main):212:0> x[0]
=> 1
irb(main):213:0> x[1]
=> 0
irb(main):214:0> x[2]
=> 0

Precedence of and/or versus method arguments in ruby

Here are two tests:
if [1,2,3,4].include? 2 && nil.nil?
puts :hello
end
#=>
and
if [1,2,3,4].include?(2) && nil.nil?
puts :hello
end
#=> hello
The above tells me that && has higher precedence than method arguments so it logically ands 2 && nil.nil? which is true and passes that as an argument to include?.
However, there is this test:
if [1,2,3,4].include? 2 and nil.nil?
puts :hello
end
#=> hello
So this is telling me that method arguments and 'and' have the same precedence (or method args are higher than 'and') since it passed 2 to include? before it processed 'and'.
Note: I understand that && and and have different precedence. The question is not regarding this but regarding and or or vs the arguments to a ruby method.
I can't find documentation that affirms this. For instances, this doesn't mention method arguments at all: http://phrogz.net/programmingruby/language.html#table_18.4 or http://romhack.wikia.com/wiki/Ruby_operators.
Could anyone explain this behavior? Namely in that how does ruby know to pass values as arguments to a method vs. process operators?
As you said && and and have different precedence, however the explanation for the following example:
if [1,2,3,4].include? 2 and nil.nil?
puts :hello
end
#=> hello
is the binding strenght of the and as you can read here:
Difference between "and" and && in Ruby?
This basically explains that 2 and nil.nil? will be evaluated as nil, however it will return 2 as can be seen in this example:
foo = :foo
bar = nil
a = foo and bar
# => nil
a
# => :foo
a = foo && bar
# => nil
a
# => nil
I've never seen any documentation about method argument precedence, but one rule of thumb I use when seeing method arguments is to mentally strip the whitespace wherever possible in the arguments and still have the same expression. This normally gives me the precedence:
[1,2,3,4].include? 2&&nil.nil? is the same expression, but you cannot strip the whitespace in
[1,2,3,4].include? 2 and nil.nil? and therefore, the precedence is left to right ... I.e. Method argument is 2.
Anyway, the better question is why on earth would you write statements like this?
Omitting method parenthesis is only useful for code readability. However, your statements are hardly readable and makes one pause over the code and think about it more than he should. If I was to review code like this, I would definitely fail the code review due to poor readability.
In fact, many style guides explicitly state that most methods with arguments should be parenthesized (is this even a word ;). For example:
Ruby style guide

Simple sort in Ruby without using sort method (note that the list to be sorted is "strings")

Given
30.02 -88.87 10.58 -99.22 107.33
to sort without the sort method. I have spent a few hours on this without any success.
def simple_sort(list) # I have to start with this method
list = list.split(' ') # I understand i need to .split to get arrays
Because they're floats I need a way to make them floats with to_f method .each(&:to_f) I saw this before but I'm not sure I understand the ":". I thought colon made objects symbols so anyone please explain (&:to_f) to me?
sorted_list = [] #thought of creating an empty array to store the new list
This is the part that gets tricky! Where do I go from here?
I want to go through each item in the array, find the smallest number and add it to the sorted_list
def sort_list(list)
list = list.split(' ').map(&:to_f)
sort = []
while sort.length < list.length
sort << list.min
list.delete(list.min)
end
sort = sort.join(' ')
return sort
end
instead of using the <=>, what would make this code work?
Open IRB and try things:
>> foo = '30.02 -88.87 10.58 -99.22 107.33'
"30.02 -88.87 10.58 -99.22 107.33"
>> foo.split
[
[0] "30.02",
[1] "-88.87",
[2] "10.58",
[3] "-99.22",
[4] "107.33"
]
So split breaks the string on whitespace, so far so good.
>> foo.split.each(&:to_f)
[
[0] "30.02",
[1] "-88.87",
[2] "10.58",
[3] "-99.22",
[4] "107.33"
]
Hmm... the values didn't change so each might not be doing what you think it does. Trying map instead:
>> foo.split.map(&:to_f)
[
[0] 30.02,
[1] -88.87,
[2] 10.58,
[3] -99.22,
[4] 107.33
]
Once the values are converted to floats then it becomes easy to sort them.
Note: You can use the <=> operator (AKA "spaceship") to tell you whether one is less-than, equal, or greater-than another, which makes it easy to know when you should swap them. For instance:
0 <=> 1 # => -1
1 <=> 1 # => 0
2 <=> 1 # => 1
You should read the documentation for the Comparable module, which makes it really easy to add additional functionally to a class by defining the <=>(other) method.
map allows us to modify/transform an array's elements, whereas each only iterates over them. You can use each to mess with the elements, but it's not generally what you want to do since map! makes it easier to transform things.
Regarding &:to_f. This was a hack on Ruby's symbols a while back, that was added to Rails. It turned out to be so useful that it was pulled into Ruby itself. It's called a "symbol to proc" and is discussed in "Ruby ampersand colon shortcut".

Resources