2

Today I've seen |= for the first time and I'm trying to understand how it works and when it can be useful.

Some experiments show:

var |= nil
# => false
var |= false
# => false
var |= true
# => true
var |= 1
# => true
var |= nil
# => true
var |= false
# => true
var
# => true

Found in Github's html-pipeline gem.

  def link_to_mentioned_user(login)
    result[:mentioned_usernames] |= [login]
    url = File.join(base_url, login)
    "<a href='#{url}' class='user-mention'>" +
    "@#{login}" +
    "</a>"
  end

I'm assuming that |= works like a guarded assignment with ||=, but casts the return value of the expession to be assigned to a boolean. This means as long as var is falsy or undefined, the expression gets evaluated and the return value cast to a boolean gets assigned. As soon as var |= some_truthy_expression is called, var will be true and further calls to var |= expression_will_not_be_called will not evaluate the expression.

  1. Does it work like that, where can one find |= in the Ruby docs?
  2. When can |= come in handy?
Thomas Klemm
  • 10,678
  • 1
  • 51
  • 54
  • I guess the question comes down to part 1. If it works like that, the short-cutting of redundant evaluations would be "handy", right? – Thilo Aug 06 '13 at 22:40
  • Posted wrong reference before. This one is about OR abbreviated assigment http://stackoverflow.com/q/8569039/422353 – madth3 Aug 06 '13 at 22:51

3 Answers3

5

For a given operator op, something like:

a op= b

is more or less shorthand for:

a = a op b

What | means is, of course, dependent on what you're |-ing:

In your case:

result[:mentioned_usernames] |= [login]

You're probably working with arrays, the array on the RHS is the give away. The result is that result[:mentioned_usernames] will have login added to it if it isn't there already. There's also a side effect: |= will remove duplicates from result[:mentioned_usernames]; for example:

>> a = [1,2,3,4,4]
=> [1, 2, 3, 4, 4]
>> a |= [1]
=> [1, 2, 3, 4]
mu is too short
  • 426,620
  • 70
  • 833
  • 800
2

foo |= bar expands to foo = foo | bar, which calls the | method on the object foo with the argument bar. So the relevant documentation would be the documentation for the | operator in whatever the class of foo is.

If the left operand of | is a boolean or nil, it will perform a logical "or" operation. It will have the same result as || except that it will always return a boolean. Another difference with || is that it will not short-circuit. It is a method call, so both the receiver and the argument will be evaluated before the method body is executed.

If the left operand of | is an integer, the right operand must also be an integer and the result will be the bitwise or of the two integers.

If the left operand is an array or set, the right operand must also be an array or set and the result will be the set union of the two arrays or sets (similarly & will be the set intersection).

If the left operand is a class that does not define a | method (which will be the case for most standard classes that I did not mention here), you will get a NoMethodError.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
1

Found help in Ruby |= assignment operator.

a |= b is equivalent to a = a | b, thus a shorthand to union arrays.

When used as in the example codebase:

results ||= []
results |= ['item'] # shorthand for results = results | ['item']
results #=> ['item']

# Array union excludes duplicates and preserves the order from the original array
results |= ['item']
results #=> ['item']

Thanks for all your help. It's quite incredible what one can learn by asking questions :)

Community
  • 1
  • 1
Thomas Klemm
  • 10,678
  • 1
  • 51
  • 54