- 0 Talk
-
Ruby operators
These links redirect here: Ruby operator, Ruby operator precedence, Ruby order, Ruby order of operations.
This page is about the operators in Ruby 1.9.
Contents |
Operator precedence
Edit
When Ruby encounters two operators, and must evaluate one operator to use the result with the other operator, then the Ruby operator precedence, or Ruby order of operations, determines the first operator to evaluate.
- So 2 + 2 * 2 acts like 2 + (2 * 2), because multiplication * has precedence before addition + in Ruby.
- So 2 + 2 == 2 * 2 acts like (2 + 2) == (2 * 2), because equality == has the lowest precedence; but 2 + 2 happens before 2 * 2, because Ruby does not need the result from 2 * 2 to compute 2 + 2.
The order in Ruby is like the order in C language or in Perl, but is not exactly the same. Ruby has higher precedence for & | ^.
| Operator | Associativity |
| -1.9 | not associative |
| () [] {} defined?() not() super() yield()
'' "" `` // %Q %q %W %w %x %r %s << <<- begin if unless while until case class module def (control structures) | not associative |
| . ::
[] (method) | left to right |
| ! ~ + (unary) | right to left |
| ** | right to left |
| - (unary) | right to left |
| * / % | left to right |
| + - (binary) | left to right |
| << >> | left to right |
| & | left to right |
| | ^ | left to right |
| > >= < <= | left to right |
| <=> == === != =~ !~ | not associative |
| && | left to right |
| || | left to right |
| .. ... | not associative |
| ?: | right to left |
| rescue (modifier) | left to right |
| = **= *= <<= >>= &&= &= ||= |= += -= /= ^= %= | right to left |
| defined? | not associative |
| , => : | not associative |
| not | right to left |
| or and | left to right |
| if unless while until (modifier) | unknown |
| ; | left to right |
Operator associativity
Edit
Operator associativity is the order of evaluation in situations like a - b - 3.
- Subtraction is left associative, so a - b - 3 acts like (a - b) - 3.
- Assignment is right associative, so a = b = 3 acts like a = (b = 3).
- Equality is not associative, so a == b == 3 raises SyntaxError.
Details
Edit
TODO
Literals
Edit
| Operator | Associativity |
| -1.9 | not associative |
A minus sign starting a literal Float or Integer, as in -1.9 or -0x8000, has a higher precedence than the unary minus operator.
- So -1.9.abs acts like (-1.9).abs, because a literal has more precedence than a method call;
- but -x.abs acts like -(x.abs), because the unary minus operator has less precedence than a method call.
0> -1.9.abs => 1.9 0> x = 1.9 => 9 0> -x.abs => -1.9
Circumfix brackets
Edit
| Operator | Associativity |
| () [] {} defined?() not() super() yield() ->
'' "" `` // %Q %q %W %w %x %r %s << <<- begin if unless while until case class module def (control structures) | not associative |
The operators with the most precedence are parentheses (), and everything that has the same precedence as parentheses. These operators have an opening bracket and a closing bracket. These are circumfix operators, because they surround (circumscribe) their operands.
Parentheses
Edit
You can use parentheses to control the order of operations. If you want addition before multiplication, you can write (2 + 2) * 2.
0> (2 + 2) * 2 => 8
Parentheses may contain multiple statements (like a progn in Common Lisp). Parentheses take the value of the last statement.
0> 2 + (puts "ROM hacking"; 2)
ROM hacking
=> 4
0> 2 + (sum = open("mario-paint.sfc") { |f| f.read }.sum 16
1> printf "Checksum of Mario Paint is x%04x\n", sum
1> 2)
Checksum of Mario Paint is x4b9e
=> 4
Parentheses, that contain zero statements, return nil.
0> () => nil
Parentheses act differently where they collect arguments to methods. The method arguments may not contain any operators below , or => in precedence.
Other brackets
Edit
Square brackets [] either make an array literal, or collect arguments to the [] method. You use the comma , to separate the array elements or method arguments.
0> ["ROM", "hacking", "is", "fun"][1,3] => ["hacking", "is", "fun"]
Curly braces {} make a hash literal. You use the arrow => to map keys to values, and use the comma , to separate the key-value pairs.
0> {"Mario Paint" => File.stat("mario-paint.sfc").size,
1* "Skipp and Friends" => File.stat("saf.sfc").size}
=> {"Mario Paint"=>1048576, "Skipp and Friends"=>1048576}
Quotes
Edit
Quotes make a string literal. Some quotes allow interpolation.
0> %q<2 + 2 * 2 is #{2 + 2 * 2}>
=> "2 + 2 * 2 is \#{2 + 2 * 2}"
0> %Q<2 + 2 * 2 is #{2 + 2 * 2}>
=> "2 + 2 * 2 is 6"
0> "the #{result = 2 + 2 * 2; "result"} is " + result.to_s
=> "the result is 6"
0> %x<#{%x<echo echo>.chomp} shell command>
=> "shell command\n"
Control statements
Edit
In a list of operators, I would probably never mention control statements like if or while. I mention them for Ruby, because Ruby allows them inside expressions. The first keyword acts as an opening bracket; the end keyword acts as a closing bracket; so control statements act as circumfix operators, and have the same precedence as parentheses.
You can use begin and end like parentheses, but you can also add rescue and else clauses.
0> 2 + begin; puts "ROM hacking"; 2; end
ROM hacking
=> 4
0> 2 + begin
1* sum = open("mario-paint.sfc") { |f| f.read }.sum 16
1> printf "Checksum of Mario Paint is x%04x\n", sum
1> 2
1> end
Checksum of Mario Paint is x4b9e
=> 4
You can also put any of begin if unless while until case class module def in expressions.
0> "I tell you that " + if 5 > 3
1> "five is greater than three"
1> else
1* "you redefined Fixnum#> method"
1> end + "!"
=> "I tell you that five is greater than three!"
0> letter = ?x
=> "x"
0> "%#{letter} is for " + case letter
1> when ?q; "'single quotes'"
1> when ?Q; '"double quotes"'
1> when ?w; "single-quoted array of words"
1> when ?W; "double-quoted array of words"
1> when ?x; "`shell commands`"
1> when ?r; "/regular expressions/"
1> when ?s; ":symbols"
1> end
=> "%x is for `shell commands`"
Dots and colons
Edit
| Operator | Associativity |
| . ::
[] (method) | left to right |
We use the dot . operator to call methods.
- The dot is left associative. So 3.next.next acts like (3.next).next, not 3.(next.next).
irb(main):006:0> 3.next.next => 5 irb(main):007:0> (3.next).next => 5 irb(main):008:0> 3.(next.next) SyntaxError: ...
Calls to the [] method, whether you write a[b] or a.[](b), have the same precedence as the dot.
- The [] operator is also left associative. So a[1][2] acts like (a[1])[2], not a([1][2]).
0> a = ["this", ["is", "a", "literal"], "array"] => ["this", ["is", "a", "literal"], "array"] 0> a[1][2] => "literal" 0> a.[](1).[](2) => "literal" 0> a[1].[](2) => "literal" 0> a.[](1)[2] => "literal"
The double-colon :: operator accesses the constant member of a module or class. For example, the Encoding class has a Encoding::Converter member. Encoding::Converter is also a class, and has a member Encoding::Converter::INVALID_MASK.
- The double-colon is left associative. So Encoding::Converter::INVALID_MASK acts like (Encoding::Converter)::INVALID_MASK.
The double-colon works with any object that is a class or module.
0> Class.new { ROM = "Read-Only Memory" }::ROM
=> "Read-Only Memory"
If we define A::B.c to return File, then A::B.c::EXCL returns File::EXCL.
- So A::B.c::EXCL acts like ((A::B).c)::EXCL, not A::(B.c)::EXCL nor (A::B).(c::EXCL). This shows that the dot and the double-colon have the same precedence.
0> module A 1> module B 2> def self.c; File; end 2> end 1> end => nil 0> A::B.c::EXCL => 2048 0> ((A::B).c)::EXCL => 2048 0> A::(B.c)::EXCL NameError: uninitialized constant B ... 0> (A::B).(c::EXCL) NameError: undefined local variable or method `c' for main:Object ...
We can use the dot to call class methods or module methods (which are singleton methods of that class object or module object), or we can use the double-colon. So A::B::c::EXCL does work. So File.stat and File::stat are equivalent.
0> A::B::c::EXCL
=> 2048
0> File.stat("n-warp-daisakusen-1.0.sfc").size
=> 2097152
0> File::stat("n-warp-daisakusen-1.0.sfc").size
=> 2097152
If the object is not a class or module, then the double-colon can still call methods, like the dot does. We seem can replace any dot with a double-colon! (But not dots in floating-point literals.)
0> -1.9.abs => 1.9 0> -1.9::abs => 1.9 0> -1::9::abs SyntaxError: ... 0> 2::+(2::*(2)) => 6
My habit is to use the dot, never the double-colon, for all method calls; but you can use either way. The one exception is that if a constant and a method have the same name (though that almost never happens), then the double-colon returns the constant, so you must use the dot to call the method.
0> module A 1> B = 3 1> def self.B; 5; end 1> end => nil 0> A::B => 3 0> A.B => 5 0> A.const_get :B => 3 0> A.method(:B).call => 5
Reference
Edit
- ruby-1.9.1-p129/parse.y, including the "precedence table"