Skip to content

Operators

datanorris edited this page Jan 24, 2016 · 25 revisions

Class-defined operators

Unary operators

  • (unary minus)
  • (unary +) ~

! not

Binary arithmetic operators

& (binary & or formal block arg)

  • (binary minus) %
  • (binary *) ** / (binary /) ^ |
  • (binary +) << (left shift)

Match operators

=~ !~

Comparison operators

<

= <= <=> == != ===

Language-defined operators

The following operators are defined by the language - their behaviour can't be altered.

Simple assignment

<lhs> = <value>
<lhs> = <asgn_value> rescue <resc_value>

Returns: The value assigned

Same as other languages - assigns a value to a variable. <lhs> can be:

  • a local variable
  • an instance variable
  • a class variable
  • a global variable
  • an array reference
  • an attribute reference
  • a constant reference

Note that a local variable in <lhs> which did not previously exist will be created by this expression. That same local variable can actually be used as part of the <value> expression - its value in such usage will be nil.

In some circumstances a rescue modifier may be attached to the assignment expression, whereas normally they can only be applied to whole statements. This results in the value of <asgn_value> rescue <resc_value> being assigned to the variable. See the operator precedence section for rules on when this is permitted.

Multiple right-hand-side assignment

<lhs> = <mrhs>

Returns: the value of <mrhs> as encapsulated in an Array

<mrhs> is a comma-separated list of regular and splat call arguments, and is processed similar to a method call. The resulting list of values is put in an Array, and this value is assigned to the <lhs>. In other words, this syntax is equivalent to assigning an array literal with <lhs> = [ <mrhs> ] except that the <mrhs> syntax does not permit hash associations or trailing commas.

Multiple left-hand-side assignment

<mlhs> = <value>
<mlhs> = <mrhs>

Returns: the value of <value> or <mrhs>

Multiple comma-separated variable references are provided in <mlhs>, and the value to be assigned is treated as an Array, its contents assigned to variable references in <mlhs>. Any variable references permitted in a simple assignments are also permitted in multiple left-hand-side assignments.

<mlhs> is a comma-separated list of at least 1 of the following elements, in order:

  • 0 or more nested "mandatory" variable references, which may be (in any order):
  • Simple variable references
  • Nested multiple left-hand-side structures enclosed in ( and )
  • An optional "rest" variable reference, which may be:
  • A regular "rest" variable reference, which is written as a variable reference prefixed by * (e.g. *rest)
  • An anonymous "rest" reference, which is written as *
  • If a "rest" variable reference is present
  • 0 or more "post" variable references, which have the same form as nested "mandatory" variable references

Nested multiple left-hand-side structures have the same form as <mlhs>.

Some additional syntax rules apply:

  • If <mlhs> or a nested multiple left-hand-side structure contains only "mandatory" references, it may be followed by a trailing ,
  • If there is only a single "mandatory" reference, it MUST be followed by a trailing ,
  • <mlhs> (excluding nested structures) may optionally be enclosed in ( and ), without changing the meaning of the expression (i.e. without it being considered a nested expression). Note that this means that a, b = c and (a, b) = c mean the same thing, however ((a, b)) = c is different.

A value is assigned to <mlhs> as follows:

  • Convert the value to Array if necessary:
  • If the value is already an Array or an instance of a subclass of Array, OK
  • Otherwise, conversion to an Array is attempted by calling the to_ary method on the value
    • If the to_ary method call fails to resolve or returns nil, the conversion has failed
    • If the returned object from to_ary is not a subclass of Array, an exception is thrown
    • Otherwise, OK
  • If the conversion failed (without throwing an exception), then the conversion is effected by creating a new Array of 1 element, which is the value
  • The contents of the array are assigned to:
  • "mandatory" variable references, from left to right, then
  • if a "rest" reference is present, any values in the array in excess of the number of mandatory/post references are selected and:
    • if the "rest" reference is anonymous, ignored
    • otherwise, compiled into an array and assigned to the "rest" reference
  • "post" variable references, from left to right
  • if there are fewer elements in the array than there are mandatory/post variable references, the unset references are set to nil
  • Any remaining values in the array are ignored
  • If there is a regular "rest" variable reference and no array elements to assign to it, it is assigned an empty array
  • If there are nested multiple left-hand-side structures in mandatory or post, this array conversion and assignment process is repeated for them

Some examples:

a, b = [1, 2, 3] # a = 1, b = 2
a, *, (b, c) = [1, 2, 3, [4, 5]] # a = 1, b = 4, c = 5

Complex assignment

&&= ||=

|= %= &= **= *= ^= -= += /= <<=

=

Logical operators

&& || ? (ternary ?:) and or

defined?

defined?

Range constructors

Also for flipflops

.. ...

Operator precedence

Broadly, the following table describes the precedence of Ruby operators.

No|Type/Associativity|Description|Operators ---|---|---|---|--- 1|Binary left|Reference|. :: 2|Unary|General|! ~ + 3|Binary right|Power|** 4|Unary|Minus|- 5|Binary left|Products|* / % 6|Binary left|Additions|+ - 7|Binary left|Shifts|<< >> 8|Binary left|Bitwise and|& 9|Binary left|Bitwise or|| ^ 10|Binary left (TODO why?)|Directional comparisons|> >= < <= 11|Binary none|General comparisons|<=> == === != =~ !~ 12|Binary left|Logical and, argument form|&& 13|Binary left|Logical or, argument form||| 14|Binary left|Range constructors|.. ... 15|Ternary right|Logical ternary|?: 16|Unary|Defined|defined? 17|Binary none|Assignment modifier|rescue 18|Binary right|Assignments|= += -= etc. 19|Unary|Logical not, expression form|not 20|Binary left|Logical and/or, expression form|and or 21|Binary left|Statement modifiers|if unless while until rescue

Some special rules also apply:

  • If a rescue modifier is applied to an assignment, e.g. <lhs> = <rhs> rescue <value>, rescue becomes an assignment modifier and takes precedence over the assignment operator (i.e. it will be interpreted as <lhs> = ( <rhs> rescue <value> )) according to the following rules:
  • The assignment operator may be simple or complex
  • This does not apply to an assignment with a multiple left-hand-side, a multiple right-hand-side or a command call on the right-hand-side
  • If the argument to defined? or not? is within parentheses and there is no whitespace preceding it, then the operator has the highest precedence (higher even than . and ::)

Clone this wiki locally