36

Recently, I came across a problem that required me to define the logical "OR" operator programmatically, but without using the operator itself.

What I came up with is this:

OR(arg1, arg2)
  if arg1 = True and arg2 = True
     return True

  else if arg1 = True and arg2 = False
     return True

  else if arg1 = False and arg2 = True
     return True

  else:
     return False

Is this logic correct, or did I miss something?

logicNoob
  • 511
  • 4
  • 6
  • Only that I looked up "how to define 'or' logically" for about half an hour and didn't find anything, so if its in wikipedia, thanks for the link :D – logicNoob Dec 16 '14 at 16:30
  • 10
    @gnat: To be fair, a truth table lists the outputs for each combination of the inputs and the Wikipedia article gives a description of the function. I think what the OP is really asking is how to define a logical OR _programmatically_ without the use of the operator itself. – Blrfl Dec 16 '14 at 16:33
  • 1
    @Blrfl I can't read asker's mind, I can only see what is written in the question: "Is this logic correct?" – gnat Dec 16 '14 at 16:35
  • 6
    @user3687688 Can you please clarify the primitives we are allowed to use? – fredoverflow Dec 16 '14 at 16:56
  • If you are interested in this kind of stuff, I think you’ll love this book: http://nand2tetris.org/ – Júda Ronén Dec 16 '14 at 19:02
  • Nitpicking: There's another problem with your solution. Popular languages use short-circuit evaluation for `or`. That means that if `arg1` is true, `arg2` is not evaluated. This comes in to play when you have something like `or(foo(), bar())`. If foo() returns true, bar() is not even called because its result isn't necessary. The problem is that usually all function arguments are evaluated when a function is called, so `arg1` and `arg2` are evaluated regardless of how you implement `Or`. In c++ you can use a macro. In C# you could use an Action as an argument. Or you could use classes. – user2023861 Dec 16 '14 at 19:05
  • 4
    this question has started a collective spasm of micro-optimization ;) – sea-rob Dec 16 '14 at 19:10
  • 1
    @RobY at [Code Golf](http://codegolf.stackexchange.com/help/on-topic), a question like this would likely be voted down for being boring and quickly closed as lacking "objective primary winning criterion". But Programmers regulars seem to simply lack experience of handling code-golfey topics (not that I complain, I like it that code-golf stuff rarely leaks in here, especially since there is a dedicated site for those willing to really enjoy stuff like that) – gnat Dec 16 '14 at 19:16
  • 8
    You could use the ternary operator `return arg1 ? arg1 : arg2;` – Matthew Dec 16 '14 at 19:58
  • 4
    I have got to know why you needed to re-define the `or` operator. – Kyle Strand Dec 17 '14 at 00:20
  • 1
    @Kyle Strand It was to make an or function for a strange pseudo 4th gen language in some code for work, and I got curious to see what the logic would be if I could't use the or operator. – logicNoob Dec 17 '14 at 02:56
  • 1
    @Matthew I doubt his language has `?:` if it doesn't even have `or` :) – fredoverflow Dec 17 '14 at 10:21
  • I am surprised no one asked if this was homework... I thought it was when I saw the title on the hot topics list. – Ryan Dec 19 '14 at 21:48
  • 3
    True and False are usually represented as 1 and 0, with this you can compute the boolean functions with integer operations. `OR(a,b) = a+b-a*b`, `AND(a,b) = a*b`, `NOT(a) = 1-a` – DenDenDo Dec 20 '14 at 23:34
  • Is it against the rules to use bitwise or? – Alejandro Dec 22 '14 at 04:52
  • If not, then assuming that `arg1` and `arg2` are boolean expressions, and convertible to integral types such as `int`, wouldn't returning the bitwise OR of the two expressions effectively have the same effect as logical OR? – Alejandro Dec 22 '14 at 12:25

14 Answers14

148

Here is a solution without or, and, not, comparisons and boolean literals:

or(arg1, arg2)
  if arg1
    return arg1
  else
    return arg2

It probably doesn't get much more fundamental than that ;)

fredoverflow
  • 6,854
  • 8
  • 39
  • 46
  • Darn, I somehow didn't see this when scanning the existing answers to see if my answer was covered. A well, have a +1. – Jon Hanna Dec 16 '14 at 18:22
  • 32
    +1 for a slightly shorter answer than mine. However I'd be tempted to drop the "else" as well just for elegance. – Elliot Blackburn Dec 16 '14 at 20:10
  • 10
    @BlueHat But then the two returns would be indented differently ;) – fredoverflow Dec 17 '14 at 10:26
  • 5
    I would like to get an EUR each time someone compares something against `true` or `false`. – JensG Dec 17 '14 at 15:51
  • 1
    @JensG Well, where do you think Bill Gates' income comes from? – This company is turning evil. Dec 17 '14 at 16:24
  • @JensG Agreed in general, but I have stumbled upon one good use case of comparing against `false`, namely `if (someCollection.add(someElement) == false)`, which means "if adding the element did not work", and it reads a lot more natural to me than negating via `!`. – fredoverflow Dec 17 '14 at 18:56
  • 1
    JavaScript `||` operator in a nutshell (when implemented in a dynamically typed language). – rhino Dec 17 '14 at 19:31
  • @FredOverflow I've never been a fan of the `if(!x)`, I find it very easy to skip over and miss when reading code. I think being verbose with == false makes a lot more sense. Where possible always comparing to true tends to read better in my books. – Elliot Blackburn Dec 17 '14 at 23:29
  • I disagree that skipping the else is more elegant. I would also elide else when the conditions are asymmetric, i.e. the if part handles exceptional situation. But when the if part and else part are symmetric, as in here, I would spell out the else. – Lie Ryan Dec 21 '14 at 21:47
  • 1
    `return arg1 if arg1 else arg2`? – Soham Chowdhury Dec 22 '14 at 04:32
  • @octatoan Sure, if his language supports that... which I doubt. – fredoverflow Dec 22 '14 at 10:44
  • 1
    The language of this answer looked like Python to me. – Soham Chowdhury Dec 22 '14 at 11:07
107

One line of code:

return not (not arg1 and not arg2)

No branching, no OR.

In a C-based language, it would be:

return !(!arg1 && !arg2);

This is simply an application of De Morgan's laws: (A || B) == !(!A && !B)

  • 6
    I think this approach is the best solution since (in my opinion) an `if/else` construct is the same as using OR, just with a different name. – Nick Dec 16 '14 at 21:12
  • 2
    @Nick using `if` is equivalent to equality. Normally in machine code an `if` is implemented as arithmetic followed by a comparison to zero with a jump. –  Dec 16 '14 at 21:17
  • 6
    For reference: http://en.wikipedia.org/wiki/De_Morgan%27s_laws – Mephy Dec 16 '14 at 23:08
  • 1
    I like this approach because it short-circuits IFF `and` short circuits, thus providing consistency among the operators. – Kyle Strand Dec 17 '14 at 00:21
  • @Mephy in the future you can edit an answer to add details such this. At your rep level the edit will need to be reviewed, but it is an encouraged way to contribute to the site. This time I added it myself. –  Dec 17 '14 at 15:29
  • 1
    @Snowman That's true. I meant that `if (a) return true; else if (b) return true;` seems more or less morally equivalent to `if (a OR b) return true;`, but that view may well be open to dispute. – Nick Dec 17 '14 at 17:31
  • 1
    The catch with this approach is that it breaks the convention in many languages that, eg, `0 or 'abc'` should give `'abc'`, not `true` – sapi Dec 18 '14 at 02:01
  • @sapi True, but I prefer to work with languages with sane boolean operators (aka "the actual boolean operators") – Andres F. Dec 18 '14 at 19:43
  • 1
    Well done! Kudos for using De Morgan's Law, and getting to the heart of boolean algebra! You can create __any__ boolean expression with suitable combinations of `NOT` and either `AND` or `OR` -- or either one of the composite `NAND` (`NOT AND`) or `NOR` (`NOT OR`) functions. – AAT Dec 19 '14 at 15:25
  • 1
    @KyleStrand, While this solution is short-circuiting, so will the implementations in other answers using `if`. Further, the short-circuiting isn't especially relevant, since both arguments have been evaluated _anyway_ as they're being passed to the "or" function. – Brian S Dec 19 '14 at 21:33
  • @BrianS Sure, though I was thinking of this more in terms of replacing `or` statements with `and` statements than as a function (despite the framing of the question). – Kyle Strand Dec 19 '14 at 22:12
102

I'd say that's correct, but could you not condense it down to something such as this?

or(arg1, arg2)
    if arg1 == true
        return true
    if arg2 == true
        return true

    return false

Since you're doing an or comparison, I don't think you really need to check the combination. It just matters if one of them is true to return true. Otherwise we want to return false.

If you're looking for a shorter version that is less verbose, this will also work:

or(arg1, arg2)
    if arg1
        return arg1
    return arg2
Elliot Blackburn
  • 1,879
  • 2
  • 15
  • 16
  • 6
    You could also remove the "else" on line 4 (leaving just `if arg2 == true`). – Dawson Toth Dec 16 '14 at 20:58
  • 1
    @DawsonToth There's many different ways you can spin it, depends if you want to be verbose or condensed really. I'd be happy with the else if but it sounds like this is a pseudo code question so I'd probably leave it like this for clarity. Very true though! – Elliot Blackburn Dec 16 '14 at 21:17
  • @BlueHat It seems slightly inconsistent to use an else if, but not an else at the end. – SBoss Dec 17 '14 at 08:43
  • @SBoss that is a fair point, I did this mostly out of habit as a some langauges complain with warnings when you don't have a return at the root of the method. However as this is a pseudo question you're probably right about clarity. I'll remove the else from line 4 as suggested. – Elliot Blackburn Dec 17 '14 at 08:55
  • I simplified it down for you. (I also changed `true` to `arg1` to make it work better with non-Boolean types.) – user541686 Dec 18 '14 at 12:00
  • 1
    @Mehrdad Thanks! I've included the old answer back just because I feel it's a bit more verbose and explains the solution a tiny bit clearer. But your solution is much smaller and does the same job. – Elliot Blackburn Dec 18 '14 at 14:36
  • 1
    even better (worse): `or(a, b): a ? a : b` – sara Jan 26 '16 at 13:48
  • @kai My only gripe with that would be that this isn't a language specific question and not all languages support that short hand format. However it's totally valid in most languages and would work just as well. – Elliot Blackburn Jan 26 '16 at 16:02
13

If you only have and and not, you can use DeMorgan's law to flip around and:

if not (arg1 = False and arg2 = False)
  return True
else
  return False

... or (even more simply)

if arg1 = False and arg2 = False
  return false
else
  return true

...

And since we've all apparently become fixated on optimizing something that is almost always available as a machine instruction anyway, that boils down to:

return not(not arg1 and not arg2)

return arg1 ? true : arg2

etc. etc. etc. etc.

Since most languages provide a conditional-and, odds are the "and" operator implies a branch anyway.

...

If all you have is nand (see wikipedia):

return nand(nand(arg1, arg1), nand(arg2, arg2))

sea-rob
  • 6,841
  • 1
  • 24
  • 47
13

Functions (ECMAScript)

All you need are function definitions and function calls. You don't need any branching, conditionals, operators or builtin functions. I will demonstrate an implementation using ECMAScript.

First, let's define two functions called true and false. We could define them any way we want, they are completely arbitrary, but we will define them in a very special way which has some advantages as we will see later:

const tru = (thn, _  ) => thn,
      fls = (_  , els) => els;

tru is a function with two parameters which simply ignores its second argument and returns the first. fls is also a function with two parameters which simply ignores its first argument and returns the second.

Why did we encode tru and fls this way? Well, this way, the two functions not only represent the two concepts of true and false, no, at the same time, they also represent the concept of "choice", in other words, they are also an if/then/else expression! We evaluate the if condition and pass it the then block and the else block as arguments. If the condition evaluates to tru, it will return the then block, if it evaluates to fls, it will return the else block. Here's an example:

tru(23, 42);
// => 23

This returns 23, and this:

fls(23, 42);
// => 42

returns 42, just as you would expect.

There is a wrinkle, however:

tru(console.log("then branch"), console.log("else branch"));
// then branch
// else branch

This prints both then branch and else branch! Why?

Well, it returns the return value of the first argument, but it evaluates both arguments, since ECMAScript is strict and always evaluates all arguments to a function before calling the function. IOW: it evaluates the first argument which is console.log("then branch"), which simply returns undefined and has the side-effect of printing then branch to the console, and it evaluates the second argument, which also returns undefined and prints to the console as a side-effect. Then, it returns the first undefined.

In λ-calculus, where this encoding was invented, that's not a problem: λ-calculus is pure, which means it doesn't have any side-effects; therefore you would never notice that the second argument also gets evaluated. Plus, λ-calculus is lazy (or at least, it is often evaluated under normal order), meaning, it doesn't actually evaluate arguments which aren't needed. So, IOW: in λ-calculus the second argument would never be evaluated, and if it were, we wouldn't notice.

ECMAScript, however, is strict, i.e. it always evaluates all arguments. Well, actually, not always: the if/then/else, for example, only evaluates the then branch if the condition is true and only evaluates the else branch if the condition is false. And we want to replicate this behavior with our iff. Thankfully, even though ECMAScript isn't lazy, it has a way to delay the evaluation of a piece of code, the same way almost every other language does: wrap it in a function, and if you never call that function, the code will never get executed.

So, we wrap both blocks in a function, and at the end call the function that is returned:

tru(() => console.log("then branch"), () => console.log("else branch"))();
// then branch

prints then branch and

fls(() => console.log("then branch"), () => console.log("else branch"))();
// else branch

prints else branch.

We could implement the traditional if/then/else this way:

const iff = (cnd, thn, els) => cnd(thn, els);

iff(tru, 23, 42);
// => 23

iff(fls, 23, 42);
// => 42

Again, we need some extra function wrapping when calling the iff function and the extra function call parentheses in the definition of iff, for the same reason as above:

const iff = (cnd, thn, els) => cnd(thn, els)();

iff(tru, () => console.log("then branch"), () => console.log("else branch"));
// then branch

iff(fls, () => console.log("then branch"), () => console.log("else branch"));
// else branch

Now that we have those two definitions, we can implement or. First, we look at the truth table for or: if the first operand is truthy, then the result of the expression is the same as the first operand. Otherwise, the result of the expression is the result of the second operand. In short: if the first operand is true, we return the first operand, otherwise we return the second operand:

const orr = (a, b) => iff(a, () => a, () => b);

Let's check out that it works:

orr(tru,tru);
// => tru(thn, _) {}

orr(tru,fls);
// => tru(thn, _) {}

orr(fls,tru);
// => tru(thn, _) {}

orr(fls,fls);
// => fls(_, els) {}

Great! However, that definition looks a little ugly. Remember, tru and fls already act like a conditional all by themselves, so really there is no need for iff, and thus all of that function wrapping at all:

const orr = (a, b) => a(a, b);

There you have it: or (plus other boolean operators) defined with nothing but function definitions and function calls in just a handful of lines:

const tru = (thn, _  ) => thn,
      fls = (_  , els) => els,
      orr = (a  , b  ) => a(a, b),
      nnd = (a  , b  ) => a(b, a),
      ntt = a          => a(fls, tru),
      xor = (a  , b  ) => a(ntt(b), b),
      iff = (cnd, thn, els) => cnd(thn, els)();

Unfortunately, this implementation is rather useless: there are no functions or operators in ECMAScript which return tru or fls, they all return true or false, so we can't use them with our functions. But there's still a lot we can do. For example, this is an implementation of a singly-linked list:

const cons = (hd, tl) => which => which(hd, tl),
      car  = l => l(tru),
      cdr  = l => l(fls);

Objects (Scala)

You may have noticed something peculiar: tru and fls play a double role, they act both as the data values true and false, but at the same time, they also act as a conditional expression. They are data and behavior, bundled up into one … uhm … "thing" … or (dare I say) object!

Indeed, tru and fls are objects. And, if you have ever used Smalltalk, Self, Newspeak or other object-oriented languages, you will have noticed that they implement booleans in exactly the same way. I will demonstrate such an implementation here in Scala:

sealed abstract trait Buul {
  def apply[T, U <: T, V <: T](thn: ⇒ U)(els: ⇒ V): T
  def &&&(other: ⇒ Buul): Buul
  def |||(other: ⇒ Buul): Buul
  def ntt: Buul
}

case object Tru extends Buul {
  override def apply[T, U <: T, V <: T](thn: ⇒ U)(els: ⇒ V): U = thn
  override def &&&(other: ⇒ Buul) = other
  override def |||(other: ⇒ Buul): this.type = this
  override def ntt = Fls
}

case object Fls extends Buul {
  override def apply[T, U <: T, V <: T](thn: ⇒ U)(els: ⇒ V): V = els
  override def &&&(other: ⇒ Buul): this.type = this
  override def |||(other: ⇒ Buul) = other
  override def ntt = Tru
}

object BuulExtension {
  import scala.language.implicitConversions
  implicit def boolean2Buul(b: ⇒ Boolean) = if (b) Tru else Fls
}

import BuulExtension._

(2 < 3) { println("2 is less than 3") } { println("2 is greater than 3") }
// 2 is less than 3

This BTW is why the Replace Conditional With Polymorphism Refactoring always works: you can always replace any and every conditional in your program with polymorphic message dispatch, because as we have just shown, polymorphic message dispatch can replace conditionals by simply implementing them. Languages like Smalltalk, Self and Newspeak are existence proof of that, because those languages don't even have conditionals. (They also don't have loops, BTW, or really any sort of language built-in control structures except for polymorphic message dispatch aka virtual method calls.)


Pattern Matching (Haskell)

You could also define or using pattern matching, or something like Haskell's partial function definitions:

True ||| _ = True
_    ||| b = b

Of course, pattern matching is a form of conditional execution, but then again, so is object-oriented message dispatch.

Jörg W Mittag
  • 101,921
  • 24
  • 218
  • 318
  • 2
    How about `False ||| False = False` and `_ ||| _ = True` instead? :) – fredoverflow Dec 17 '14 at 10:25
  • 3
    @FredOverflow: That would require always evaluating the right operand. Usually Boolean operators are expected to be non-strict in their right argument aka "short-circuiting". – Jörg W Mittag Dec 17 '14 at 13:38
  • Ah, of course. I knew there had to be a deeper reason :) – fredoverflow Dec 17 '14 at 18:58
  • The first part reminded me immediately of Eric Lippert's great series about [continuation passing style](http://blogs.msdn.com/b/ericlippert/archive/2010/10/21/continuation-passing-style-revisited-part-one.aspx). Purely coincidental but still fun :) – Voo Dec 17 '14 at 20:43
  • 1
    @JörgWMittag FredOverflow's definition is appropriately short-circuiting. Try `True ||| undefined` yourself in ghci to see! – Daniel Wagner Dec 18 '14 at 07:34
  • @DanielWagner: now, try `False ||| undefined`. The result of `False ||| anything` is uniquely determined by `anything`, and thus, as long as you don't look at `anything`, this should work. Only when you actually look at `anything` (i.e. `undefined` in this case), should it blow up. I agree that "short-circuiting" is not the best term to describe this behavior. I should have left it at "non-strict in its right argument". – Jörg W Mittag Dec 18 '14 at 13:33
  • @JörgWMittag Your definition of `|||` also blows up when you try `False ||| undefined`. – Daniel Wagner Dec 18 '14 at 19:40
  • @JörgWMittag As you can see [in this ideone](http://ideone.com/huSPUC), FredOverflow's implementation has exactly the same denotation as yours. – Daniel Wagner Dec 18 '14 at 22:18
  • have a +1 for `Buul` – Soham Chowdhury Dec 22 '14 at 04:34
3

Another way to express the logical operators as an integer arithmetic expressions (where feasible). This way can avoid lots of branching for a larger expression of many predicates..

Let True be 1 Let False be 0

if the summation of both is greater than 1 then it is true or false to be returned.

boolean isOR(boolean arg1, boolean arg2){

   int L = arg1 ? 1 : 0;
   int R = arg2 ? 1 : 0;

   return (L+R) > 0;

}
  • 6
    `booleanExpression ? true : false` is trivially equal to `booleanExpression`. – Keen Dec 16 '14 at 22:02
  • I like your methodology but a simple mistake is that the sum of both arguments must be greater than ZERO to be true, not greater than ONE. – Grantly Dec 16 '14 at 22:15
  • 1
    `return (arga+argb)>0` – Grantly Dec 17 '14 at 01:06
  • I just thought you might want to revise this point you wrote: "if the summation of both is greater than 1 then it is true or false to be returned" to zero instead of 1... – Grantly Dec 17 '14 at 01:08
  • 1
    I was only correcting your text. Your code is perfect, but could be in one line: `return (((arg1 ? 1 : 0)+(arg2 ? 1 : 0)) > 0);` :) – Grantly Dec 17 '14 at 01:12
  • @Cory - I suppose you presumed the programming language to be C like? 1 <> true or 0 <> false in many other languages..for example it is not the case in Java. My intention was not to give a syntac corrected, all boundary conditions covered, well compact code..let's spare ourselves of that..it was intended to present a 'technique' rather. – Senthu Sivasambu Dec 18 '14 at 14:46
  • @Grantly thanks for pointing out the error in the text. Yes it should be "strictly greater than 0" – Senthu Sivasambu Dec 18 '14 at 14:46
  • @SenthuSivasambu In the case of your code, I made no such presumption. A comparison operation such as `>` returns a Boolean value of `true` or `false`. In general, you can trim down `true ? true : false` or `false ? true : false` because these always evaluate to `true` and `false` respectively. – Keen Dec 18 '14 at 18:07
  • 1
    @SenthuSivasambu I have no objections to your use of `arg1 ? 1 : 0;`. Those are reliable expressions for transforming a Boolean into a number. It's only the return statement that can be trivially refactored. – Keen Dec 18 '14 at 18:09
  • oh..my bad. point taken. Yes. it can be. Rookie mistake... :O – Senthu Sivasambu Dec 18 '14 at 20:55
  • @Cory I have corrected and have given credit to you for pointing out. However my comment is not appearing to me.. – Senthu Sivasambu Dec 18 '14 at 20:56
3

Here's another way to define OR, or indeed any logical operator, using the most traditional way of defining it: use a truth table.

This is of course quite trivial to do in higher level languages such as Javascript or Perl but I'm writing this example in C to show that the technique does not depend on high level language features:

#include <stdio.h>

int main (void) {
    // Define truth table for OR:
    int OR[2][2] = {
        {0,   // false, false
         1},  // false, true
        {1,   // true, false
         1}   // true, true
    }

    // Let's test the definition
    printf("false || false = %d\n",OR[1==2]['b'=='a']);
    printf("true || false = %d\n",OR[10==10]['b'=='a']);

    // Usage:
    if (OR[ 1==2 ][ 3==4 ]) {
        printf("at least one is true\n");
    }
    else {
        printf("both are false\n");
    }
}

You can do the same with AND, NOR, NAND, NOT and XOR. The code is clean enough to look like syntax such that you can do stuff like this:

if (OR[ a ][ AND[ b ][ c ] ]) { /* ... */ }
slebetman
  • 1,394
  • 9
  • 9
  • I think this is the "purest" approach in certain mathematical sense. The OR-operator is a function after all, and the truth table is really the essence of that function as a relation and a set. Of course this could be written in an amusing OO manner too: `BinaryOperator or = new TruthTableBasedBinaryOperator(new TruthTable(false, true, true, true));` – COME FROM Dec 19 '14 at 11:35
1

The two forms:

OR(arg1, arg2)
  if arg1
     return True
  else:
     return arg2

OR

OR(arg1, arg2)
  if arg1
     return arg1
  else:
     return arg2

Have as well as the code golf-like advantage of being a bit smaller than the other suggestions so far, one less branch. It's not even that silly a micro-opt to reduce the number of branches if we're considering the creation of a primitive that would hence be very heavily used.

Javascript's definition of || is akin to this, which combined with its loose typing means that the expression false || "abc" has the value "abc" and 42 || "abc" has the value 42.

Though if you already have other logical operators then the likes of nand(not(arg1), not(arg2)) might have the advantage of no branching at all.

Jon Hanna
  • 2,115
  • 12
  • 15
  • what's the point of repeating the prior answer ([as you admitted](http://programmers.stackexchange.com/questions/266592/how-to-define-or-logically/266635#comment542424_266600))? – gnat Dec 17 '14 at 08:15
  • @gnat it's close enough that I wouldn't have bothered had I seen that answer, but it does still have something to it not found in any of them, so I'm leaving it. – Jon Hanna Dec 17 '14 at 09:55
  • @gnat, actually considering "We're looking for long answers that provide some explanation and context." I'm happier with this answer now. – Jon Hanna Dec 17 '14 at 09:58
1

All the good answers have already been given. But I won't let that stop me.

// This will break when the arguments are additive inverses.
// It is "cleverness" like this that's behind all the most amazing program errors.
or(arg1, arg2)
    return arg1 + arg2
    // Or if you need explicit conversions:
    // return (bool)((short)arg1 + (short)arg2)

Alternatively:

// Since `0 > -1`, negative numbers will cause weirdness.
or(arg1, arg2)
    return max(arg1, arg2)

I hope no one would ever actually use approaches like these. They're here only to promote awareness of alternatives.

Update:

Since negative numbers can break both of the above approaches, here is another awful suggestion:

or(arg1, arg2)
    return !(!arg1 * !arg2)

This simply uses DeMorgan's Laws and abuses the fact that * is similar to && when true and false are treated like 1 and 0 respectively. (Wait, you're saying this isn't code golf?)

Here's a decent answer:

or(arg1, arg2)
    return arg1 ? arg1 : arg2

But that's essentially identical to other answers already given.

Keen
  • 151
  • 4
  • 3
    These approaches are fundamentally flawed. Consider -1+1 for `arg1+arg2`, -1 and 0 for `max(arg1,arg2)`, etc. – fluffy Dec 17 '14 at 04:36
  • @fluffy This approach assumes Boolean arguments, and then it just happens to work correctly with most kinds of garbage input. Good of you to point out that there's still some garbage which produces issues. This kind of thing is exactly why we should seek to model the actual problem domain as directly as possible (and avoid getting carried away by our own cleverness) in practice. – Keen Dec 17 '14 at 15:37
  • If you're doing pure 1-bit boolean values, then addition still doesn't work, since 1+1 = 0. :) – fluffy Dec 17 '14 at 17:14
  • @fluffy That's where the explicit conversions come in. Whether or not they're needed depends on the details of the implementation (which is exactly why this is a silly idea). – Keen Dec 17 '14 at 17:21
1

In addition to all the programmed solutions using the if construct, it's possible to construct an OR gate by combining three NAND gates. If you want to see how it's done in wikipedia, click here.

From this, the expression,

NOT[ NOT( A AND A ) AND NOT( B AND B )]

which uses NOT and AND gives the same answer as OR. Notice that the use of both NOT and AND is just an obscure way of expressing NAND.

Walter Mitty
  • 806
  • 5
  • 14
0

One way to define or is via a lookup table. We can make this explicit:

bool Or( bool a, bool b } {
  bool retval[] = {b,true}; // or {b,a};
  return retval[a];
}

we create an array with the values that the return value should have depending on what a is. Then we do a lookup. In C++ like languages, bool promotes to a value that can be used as an array index, with true being 1 and false being 0.

We can then extend this to other logical operations:

bool And( bool a, bool b } {
  bool retval[] = {false,b}; // or {a,b};
  return retval[a];
}
bool Xor( bool a, bool b } {
  bool retval[] = {b,!b};
  return retval[a];
}

Now a downside of all of these is that it requires prefix notation.

namespace operators {
  namespace details {
    template<class T> struct is_operator {};
    template<class Lhs, Op> struct half_expression { Lhs&& lhs; };
    template<class Lhs, class Op>
    half_expression< Lhs, Op > operator*( Lhs&&lhs, is_operator<Op> ) {
      return {std::forward<Lhs>(lhs)};
    }
    template<class Lhs, class Op, class Rhs>
    auto operator*( half_expression<Lhs, Op>&& lhs, Rhs&& rhs ) {
    return invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
    }
  }
  using details::is_operator;
}

struct or_tag {};
static const operators::is_operator<or_tag> OR;

bool invoke( bool a, or_tag, bool b ) {
  bool retval[] = {b,true};
  return retval[a];
}

and now you can type true *OR* false and it works.

The above technique requires a language that supports argument dependent lookup, and templates. You could probably do it in a language with generics and ADL.

As an aside, you can extend the *OR* above to work with sets. Simply create a free function invoke in the same namespace as or_tag:

template<class...Ts>
std::set<Ts...> invoke( std::set<Ts...> lhs, or_tag, std::set<Ts...> const& rhs ) {
  lhs.insert( rhs.begin(), rhs.end() );
  return lhs;
}

and now set *OR* set returns the union of the two.

Yakk
  • 2,121
  • 11
  • 10
0

This one remembers me the charasteristic functions:

or(a, b)
    return a + b - a*b

This only applies to languages which can treat booleans as (1, 0). Does not apply to Smalltalk or Python since boolean is a class. In smalltalk they go even further (this will be written in sort of a pseudocode):

False::or(a)
    return a

True::or(a)
    return self

And the dual methods exist for and:

False::and(a)
    return self

True::and(a)
    return a

So the "logic" is perfectly valid in the OP statement, althought it is verbose. Beware, it is not bad. It is perfect if you need a function which acts like a mathematical operator based on, say, a kind of matrix. Others would implement an actual cube (like a Quine-McCluskey statement):

or = array[2][2] {
    {0, 1},
    {1, 1}
}

And you will evaluate or[a][b]

So yes, every logic here is valid (except that one posted as using the in-language OR operator xDDDDDDDD).

But my favorite one is the DeMorgan's law: !(!a && !b)

Luis Masuelli
  • 864
  • 1
  • 7
  • 13
0

Look at the Swift standard library and check out their implementation of the shortcut OR and shortcut AND operations, which don’t evaluate the second operands if not needed/allowed.

gnasher729
  • 42,090
  • 4
  • 59
  • 119
-2

The logic is perfectly correct, but can be simplified:

or(arg1, arg2)
  if arg1 = True
     return True
  else if arg2 = True
     return True
  else
     return False

And presumably your language has an OR operator so - unless it's against the spirit of the question - why not

or(arg1, arg2)
  if arg1 = True or arg2 = True
     return True
  else
     return False
Julia Hayward
  • 2,872
  • 2
  • 15
  • 12
  • `if arg1 = True or arg2 = True { return true } else { return false }` Better yet, `return arg1 = True or arg2 = True`. `if condition then true else false` is redundant. – Doval Dec 16 '14 at 16:27
  • 4
    asker specifically pointed that their requirement was "without using the operator itself" – gnat Dec 16 '14 at 17:10
  • 2
    Um, I didn't say anything of the sort. It was kind of what I meant, but the question didn't say so until it was edited, and she answered it as such, so kind of my fault on that one. – logicNoob Dec 17 '14 at 02:53