11

From documentation: http://ruby-doc.org/core-2.2.0/TrueClass.html#method-i-7C

true |  puts("or")
true || puts("logical or")

# produces:

or
  • Could you explain when "single pipe" is useful?
  • What's the difference?

(only in TrueClass context (not Array or Fixnum context )

itsnikolay
  • 17,415
  • 4
  • 65
  • 64

2 Answers2

12

It is useful when you do not need eager evaluation of or statement.

For example, if you have some methods, that do something useful and returns true/false as a result, and have another method that should be called only if any of those methods returns true, it is useful to use |:

def action1
  # do something, returns true/false
end

def action2
  # do something, returns true/false
end

def result_action
  # do something 
end

result_action if action1 | action2

If you use logical || instead then if action1 returns true, action2 will not be called (result_action will be invoked though)

mikdiet
  • 9,859
  • 8
  • 59
  • 68
  • Absolutely. `puts` always returns `nil`, so both sides of `a || b` were invoked in your code @Mugur'Bud'Chirica – mikdiet Jul 14 '19 at 18:28
8

It is hard to tell why TrueClass has a #| method defined.

The fact that it is a method does mean that both of its "operands" get evaluated and then combined, which is why the string "or" was output. The double pipe is a special construct: it will not evaluate the second operand if the first was truthy. Therefore, as a way to do boolean computations, the single pipe looks useless.

Now, the operator makes a lot more sense on Fixnum: it performs the same bitwise OR as seen in C, Java, etc.

For example:

>> 133|243
=> 247

Now Java, for some reason, overloaded | on booleans to be a non-short circuit operator. Perhaps Ruby is doing a "me too"? Doesn't seem likely that Ruby would want to copy Java here.

It's more likely the case that because

true | e

evaluates to

e

for any e, Ruby is allowing you to chain together a bunch of truthy expressions. Perhaps

true | e1 | e2 | e3 | e4

looks cooler than

e1
e2
e3
e4
true

or even

e1; e2; e3; e4; true

Another possibility might be that it allows you to chain together boolean-producing expressions with side-effects.

f(x1) | f(x2) | f(x3) | f(x4)

and return whether or not any of the functions produced true. Here's a contrived example:

>> def f(x);puts x;return x==2;end
=> :f
>> f(1) || f(2) || f(3) || f(4)
1
2
=> true
>> f(1) | f(2) | f(3) | f(4)
1
2
3
4
=> true

Of course, this is still just a lame attempt because you get the same effect with:

>> [f(1),f(2),f(3),f(4)].any?
1
2
3
4
=> true

I suspect, but am not 100% sure, that the operator is included for some kind of "completeness" in the algebraic sense. Boolean algebra has AND or OR, and the || isn't really a method in the classic sense of having eager evaluation semantics. So maybe it was thrown in because of that reason, and, if any programmer happens to find a use for it, then wonderful. But I've never seen, in many years of programming, any pragmatic reason for not short-circuiting.

I would in fact argue that if someone were to write code that depended on the evaluation of the second argument in a boolean context (i.e., using #|), that such code would be confusing --- and certainly not referentially transparent, as it would rely on side effects --- and should therefore be rewritten.

Ray Toal
  • 86,166
  • 18
  • 182
  • 232
  • Mostly `#|` is a method, but `||` is an operator. – Arup Rakshit Dec 26 '14 at 15:31
  • Thanks you. But why not to write: `true && e1 && e2 && e3 && e4` ? – itsnikolay Dec 26 '14 at 16:16
  • You know, this is a _really_ good question. I'm STILL trying to figure it out myself. When I come up with something, I will add it to the answer. There are so many ways to do things. I suspect you can use this in an DSL somewhere, _somehow_, because, as you suspect, it appears to be completely useless as a boolean operator! – Ray Toal Dec 26 '14 at 16:37
  • 1
    This example I've tried `a |= puts 'hi' ; puts a ; #=> hi false` overkilled me. Where it can be useful, i still can not imagine ;) Thanks for answers. My vote up :) – itsnikolay Dec 26 '14 at 17:27
  • Just noticed http://stackoverflow.com/questions/9264897/reason-for-the-exsistance-of-non-short-circuit-logical-operators but again, I think these cases are a little convoluted and should be rewritten. – Ray Toal Dec 26 '14 at 22:03
  • Java was first publicly released in 1995, Ruby was designed in 1993, so I really doubt there's any "me-tooing" going on. AFAIK, the only thing Ruby ever took from the Java community are Refinements in Ruby 2.0, which are (very) loosely based on [Classboxes](http://scg.unibe.ch/research/classboxes). – Jörg W Mittag Dec 27 '14 at 01:19
  • It was supposed to be tongue-in-cheek, along the lines of people criticizing [Pascal for using the non-C `:=` despite the fact C wasn't invented yet](http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html). – Ray Toal Dec 27 '14 at 03:53