### 3.1 Expression evaluation order ¶

A commonly asked question about Blitz++ is what order it uses to evaluate array expressions. For example, in code such as

    A(Range(2,10)) = A(Range(1,9))

does the expression get evaluated at indices 1, 2, ..., 9 or at 9, 8, ..., 1? This makes a big difference to the result: in one case, the array will be shifted to the right by one element; in the other case, most of the array elements will be set to the value in `A(1)`.

Blitz always selects the traversal order it thinks will be fastest. For 1D arrays, this means it will go from beginning to the end of the array in memory (see notes below). For multidimensional arrays, it will do one of two things:

- try to go through the destination array in the order it is laid out in memory (i.e. row-major for row-major arrays, column-major for column-major arrays).
- if the expression is a stencil, Blitz will do tiling to improve cache use. Under some circumstances blitz will even use a traversal based on a hilbert curve (a fractal) for 3D arrays.

Because the traversal order is not always predictable, it is safest to put the result in a new array if you are doing a stencil-style expression. Blitz guarantees this will always work correctly. If you try to put the result in one of the operands, you have to guess correctly which traversal order blitz will choose. This is easy for the 1D case, but hard for the multidimensional case.

Some special notes about 1D array traversals:

- if your array is stored in reverse order, i.e. because of a A.reverse(firstDim) or funny storage order, blitz will go through the array from end to beginning in array coordinates, but from beginning to end in memory locations.
- many compilers/architecture combinations are equally fast at reverse order. But blitz has a specialized version for stride = +1, and it would be wasteful to also specialize for the case stride = -1. So 1D arrays are traversed from beginning to end (in memory storage order).

### 3.2 Expression operands ¶

An expression can contain any mix of these operands:

- An array of any type, so long as it is of the same rank. Expressions which contain a mixture of array types are handled through the type promotion mechanism described below.
- Scalars of type `int`, `float`, `double`, `long double`, or `complex<T>`
- Index placeholders, described below
- Other expressions (e.g. `A+(B+C)`)

### 3.3 Array operands ¶

#### Using subarrays in an expression ¶

Subarrays may be used in an expression. For example, this code example performs a 5-point average on a two-dimensional array:

    Array<float,2> A(64,64), B(64,64);   // ...
    Range I(1,62), J(1,62);

    A(I,J) = (B(I,J) + B(I+1,J) + B(I-1,J)
                     + B(I,J+1) + B(I,J-1)) / 5;

#### Mixing arrays with different storage formats ¶

Arrays with different storage formats (for example, C-style and Fortran-style) can be mixed in the same expression. Blitz++ will handle the different storage formats automatically. However:

- Evaluation may be slower, since a different traversal order may be used.
- If you are using index placeholders (see below) or reductions in the expression, you may not mix array objects with different starting bases.

### 3.4 Expression operators ¶

These binary operators are supported:

    + - * / % > < >= <= == != && || ^ & |

Caution: operator `<<` and `>>` are reserved for use in input/output. If you need a bit-shift operation on arrays, you may define one yourself; see Declaring your own math functions on arrays.

These unary operators are supported:

    - ~ !

The operators `> < >= <= == != && || !` result in a bool-valued expression.

All operators are applied elementwise.

You can only use operators which are well-defined for the number type stored in the arrays. For example, bitwise XOR (`^`) is meaningful for integers, so this code is all right:

    Array<int,3> A, B, C;   // ...
    A = B ^ C;

Bitwise XOR is not meaningful on floating point types, so this code will generate a compiler error:

    Array<float,1> A, B, C;   // ...
    C = B ^ C;

Here’s the compiler error generated by KAI C++ for the above code:

    "../../blitz/ops.h", line 85: error: expression must have integral or enum type
      BZ_DEFINE_OP(BitwiseXor,^);
      ^
              detected during:
                instantiation of "blitz::BitwiseXor<float, float>::T_numtype
                          blitz::BitwiseXor<float, float>::apply(float, float)" at
                          line 210 of "../../blitz/arrayexpr.h"
                instantiation of ...
                         .
                         .

If you are creating arrays using a type you have created yourself, you will need to overload whatever operators you want to use on arrays. For example, if I create a class `Polynomial`, and want to write code such as:

    Array<Polynomial,2> A, B, C;   // ...
    C = A * B;

I would have to provide `operator*` for `Polynomial` by implementing

    Polynomial Polynomial::operator*(Polynomial);)

or

    Polynomial operator*(Polynomial, Polynomial);)

### 3.5 Assignment operators ¶

These assignment operators are supported:

    = += -= *= /= %= ^= &= |= >>= <<=

An array object should appear on the left side of the operator. The right side can be:

- A constant (or literal) of type `T_numtype`
- An array of appropriate rank, possibly of a different numeric type
- An array expression, with appropriate rank and shape