Programming Style and Best Practices

Practical guidelines for writing correct and efficient MtxVec code.

1. Always use try/finally with CreateIt/FreeIt:

CreateIt(a, b);
try
    // ... use a, b ...
finally
    FreeIt(a, b);  // always executes, even on exception
end;

Never skip the try/finally — an exception will leak pool objects.

2. Mixing Vector and TVec in the same code:

var v: Vector;         // automatic lifetime
    t: TVec;           // needs CreateIt/FreeIt
begin
    v.Size(100);         // v manages itself
    CreateIt(t);
    try
        t.Size(100);
        t.Sin(v);          // OK: Vector auto-converts to TVec parameter
    finally
        FreeIt(t);
    end;
end;

3. Avoid element-by-element loops:

// BAD — slow, not vectorized
for i := 0 to a.Length - 1 do
    a.Values1D[i] := Sin(a.Values1D[i]);

// GOOD — vectorized, SIMD, potentially multithreaded
a.Sin;

The vectorized form is 10-100x faster depending on array size and operation.

4. Use compound operations when formula matches:

// BAD — 3 passes through memory, 2 temporaries
c.Mul(a, b);
c.Add(d);

// GOOD — 1 pass, no temporaries
c.MulAndAdd(a, b, d);   // c = a * b + d

5. Handle exceptions — they signal contract violations only:

An exception is raised only when a genuine violation of an operation's contract occurs. Exceptions are never used to report normal processing results:

  • Size(0) is legal — an empty vector or matrix is a valid state, not an error.
  • NAN and INF are valid floating-point values — they propagate through computations normally and raise nothing.
ClassRaised when
EMtxVecExceptionbase class of all MtxVec exceptions
EMtxVecRangeErroran index or length falls outside the valid range
EMtxVecInvalidArgumenta parameter violates the method's contract
EOutOfMemoryallocation failure

EMtxVecRangeError and EMtxVecInvalidArgument both descend from EMtxVecException, so catching the base class handles either.

// LUSolve's contract requires a full-rank matrix
try
    m.LUSolve(b, x);
except
    on E: EMtxVecException do
        ShowMessage('LUSolve failed: ' + E.Message);
end;

6. Sizing is automatic:

You never need to call Size() before writing to a vector or matrix — every operation that writes a result calls Size() on the destination implicitly, matching it to its inputs.