Boolean And
Synopsis
Boolean and operator.
Syntax
Exp₁ && Exp₂
Types
//
Exp₁ | Exp₂ | Exp₁ && Exp₂ |
---|---|---|
bool | bool | bool |
Description
The and operator on Boolean values defined as follows:
Exp₁ | Exp₂ | Exp₁ && Exp₂ |
---|---|---|
true | true | true |
true | false | false |
false | true | false |
false | false | false |
Boolean operators have short circuit semantics: only those operands are evaluated that are needed to compute the result. In the case of the &&
operator, the result is false
if Exp₁
evaluates to false
, otherwise Exp₂
is evaluated to determine the result.
Note that &&
backtracks over its argument expressions until it can find an evaluation that yields true
unless there is none. This may happen if the left or right expression is a non-deterministic pattern match or a value generator.
Variable assignments as a result of matching or generator expressions under a &&
are visible outside the context of the operator, but only if the context is conditional, such as an if-then-else or a for loop. Note that if one of the argument expressions evaluates to false, then no binding is done either.
Examples
rascal>true && false;
bool: false
rascal>i <- [1,2,3] && (i % 2 == 0)
bool: true
rascal>import IO;
ok
rascal>if (i <- [1,2,3] && (i % 2 == 0))
>>>>>>> println("<i> % 2 == 0");
2 % 2 == 0
ok
rascal>for (i <- [1,2,3,4] && (i % 2 == 0))
>>>>>>> println("<i> % 2 == 0");
2 % 2 == 0
4 % 2 == 0
list[void]: []
Benefits
- The backtracking
&&
allows one to express searching for a computational solution in concise manner.
Pitfalls
- Side effects to global variables or IO in the context of a backtracking
&&
can lead to more effects than you bargained for.
rascal>import IO;
ok
rascal>int i = 0;
int: 0
rascal>bool incr() { i += 1; return true; }
bool (): function(|prompt:///|(0,36,<1,0>,<1,36>))
rascal>for (int j <- [1,2,3] && incr() && (i % 2 == 0))
>>>>>>> println("once true for <j>");
once true for 2
list[void]: []
rascal>i;
int: 3