|, || Binary OR between integers. Logical OR over/between booleans and numbers

## Syntax

Element-wise operator:

                intMat = intA | intB
                tfMat = A | B

Scalared short-circuited evaluation:

                tf = U || V
                if (U || V) then ... end
                if (U | V)  then ... end
                while (U || V) then ... end
                while (U | V) then ... end

## Arguments

intA, intB

  Arrays of encoded integers of any inttype.

  `intA` and `intB` must have the same sizes to be processed element-wise. If `intA` or `intB` is a scalar, it is priorly replicated to the size of the other operand before processing.

  If `intA` and `intB` have not the same integer inttype, the operand with the smaller encoding is converted to the wider according to the following ranks: int8 < uint8 < int16 < uint16 < int32 < uint32 < int64 < uint64.

intMat

  Array of encoded integers with the same sizes of `intA` and `intB`, and of the wider inttype of both (see hereabove). For any index `i`, `intMat(i) = bitor(intA(i), intB(i))`

  `intA | []` and `[] | intA` return the boolean array `intA~=%nan`.
A, B

  Arrays of booleans or of numbers: encoded integers of any inttype, real or complex numbers. `A` and `B` may have distinct types, and may be one or both sparse-encoded. The special case where `A` and `B` are both encoded integers is excluded (see here-above).

  `A` and `B` must have the same sizes to be processed element-wise. If `A` or `B` is a scalar, it is priorly replicated to the size of the other operand before processing.

tfMat

  Boolean array with the same sizes of `A` and `B`. If `A` or `B` is sparse-encoded, so is `tfMat`.

  For any index `i`, `tfMat(i)` is `%T` if either `A(i)` or `B(i)` is `%T` or not zero. Otherwise, `tfMat(i)` is set to `%F`.

  `A | []` and `[] | A` return `[]`.
U, V

  Arrays of full or sparse-encoded booleans or of numbers of any types and encoding: any inttype of encoded integers, full or sparse-encoded real or complex numbers.

  `U` and `V` may have distinct data types, number of dimensions, and sizes.

tf

  single boolean: `U || V` is equal to `or(U) | or(V)`, without evaluating `or(V)` if `or(U)` is true (this is why the `||` operator is so-called short-circuited).

  See or() for the definition of the evaluation to true depending on type and encoding.

## Description

||

  For any boolean or numerical operands `U` and `V`, `G = U || V` is equivalent to

      if and(U) // none of U components is null or false
          G = %t
          // V is not assessed
      else
          G = and(V)
      end

  - `U` and `V` may have distinct sizes or numbers of dimensions.
  - The result is always a single boolean.
  - `and(V)` is evaluated only if `and(U)` is false. This mainly avoids yielding errors when further operations with `V` are meaningless or prone to error when `and(U)` is true. See examples.
  `||` is useful mainly out of `if ..` and `while ..` conditions. Otherwise, it is just equivalent to the simple `|`.
|

  When the `|` operator is used inside a logical condition tested by a `while` or by an `if` control structure, it is equivalent to the `||` operator (see above): `U|V` is equivalent to `and(U)|and(V)`, without assessing `V` if `and(U)` is true.

  Otherwise, `|` has two different actions:

  1. When both operands are encoded integers,

     `intA | intB` is processed element-wise and yields an array of integers resulting from the bitwise `AND` between corresponding components.

     Comparison with `bitor()` : `intA | intB` accepts negative integers, while `bitor(intA, intB)` does not. `bitor(A,B)` works bitwise with decimal-encoded integers.
  2. Otherwise,

     when operands are arrays of numbers or/and booleans, they are still processed element-wise. Null numbers being considered as booleans false, the result is an array of booleans.

The overloading code for `|` and `||` operators is g.

- `%nan` is `true`.
- A polynomial or rational is not considered as a number and is not an acceptable operand for `|` or `||`.

## Examples

    A = [0 1; 1 0];   // equivalent to [%f %t ; %t %f]
    B = [1 1; 0 0];   // equivalent to [%t %t ; %f %f]
    spA = sparse(A);
    spB = sparse(B);
    spbA = sparse(A<>0);
    spbB = sparse(B<>0);
    iA = int8(A);
    iB = int8(B);
    cA = A + 0*%i;
    cB = B + 0*%i;

    // | as bitwise (and elementwise) operation
    // ----------------------------------------
    // Both operands and the result are arrays of encoded integers

    iA | iB

    Ai8 = int8([ -1, 1; 127, -128]);
    // Integer representation of Ai8:
    // [ 1111 1111, 0000 0001 ;
    //   0111 1111, 1000 0000 ]

    Bi8 = int8([-2, 0; 126, -127]);
    // Integer representation of Bi8:
    // [ 1111 1110, 0000 0000 ;
    //   0111 1110, 1000 0001 ]

    Ai8 | Bi8

    // Integer promotion
    Ai16  = int16(Ai8);
    Bui32 = uint32(Bi8);

    r = Ai16 | Bui32, typeof(r)

    // | as logical elementwise operation
    // ----------------------------------
    // Operands are arrays of booleans or of numbers. The result is an array of booleans

    A | B
    A | spB    // Result is sparse encoded
    iA | spB   // Result is sparse encoded
    cA | iB
    A | %nan   // %nan is %t

    // Shorted and scalared  | or ||:
    // -----------------------------
    // Operands are arrays of booleans or of numbers. The result is a single boolean

    function res = foo()
        error("foo() shall not be called")
    endfunction

    // | (simple) is always shorted in any if's condition:
    if  %T | foo() then
        // foo() is not called and this is not executed
    end

    // || is scalared and shorted in any boolean expression, even out of if or while ones:
    T = [-2 1];
    T  || foo()        // T has only true (non zero) components, and so is "true as a whole".
    int8(T) || foo()   // Therefore, foo() as right operand is not assessed / called.
    T+0*%i || foo()

Avoiding conditional errors in `or` out of `if` and `while` conditions:

    A = [ 1 3 -2 ; 4 -1  2]
    c = ~issquare(A) | det(A)~=0
    // det(A) is evaluated despite ~issquare(A) is true (so c is true anyway)
    // But A should be square to be able to compute its det(). ==> ERROR

    // Now, we use the short-circuited || :
    // det(A) is NO LONGER computed, since ~issquare(A) is true => anyway c is true
    c = ~issquare(A) || det(A)~=0     // => NO ERROR

    // In an "if" (or "while") tested condition, | is equivalent to ||
    if ~issquare(A) | det(A)~=0       // => NO ERROR
       B = A * A.'
    end

    --> A = [ 1 3 -2 ; 4 -1  2]
     A  =
       1.   3.  -2.
       4.  -1.   2.

    --> c = ~issquare(A) | det(A)~=0
    det: Wrong type for input argument #1: Square matrix expected.

    --> c = ~issquare(A) || det(A)~=0    // => NO ERROR
     c  =
      T

    --> if ~issquare(A) | det(A)~=0      // => NO ERROR
      >    B = A * A.'
      > end
     B  =
       14.  -3.
      -3.    21.

Constant polynomials or rationals can't be processed with | or ||:

    p = 1 + 0*%z
    typeof(p)
    p | 1

    --> p = 1 + 0*%z
     p  =
       1

    --> typeof(p)
     ans  =
     polynomial

    --> p | 1
    Undefined operation for the given operands.
    check or define function %p_g_s for overloading.

## See also

- or
- bitor
- and operator (&)
- not ~
- if
- while
- overloading

## History

6.0 || operator added