Programming Style and Best Practices

Practical guidelines for writing correct and efficient MtxVec code.

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

TVec* a = nullptr;
TVec* b = nullptr;
CreateIt(a, b);
try
{
    // ... use a, b ...
}
catch (...)
{
    FreeIt(a, b);  // runs when an exception leaves the block ...
    throw;
}
FreeIt(a, b);      // ... and this one on the normal path

In C++ both FreeIt calls are required — the one in the catch (...) block and the one after it — or an exception leaks pool objects. Vector and Matrix need neither.

2. Mixing Vector and TVec in the same code:

Vector v;                     // automatic lifetime
v.Size(100);                  // v manages itself

TVec* t = nullptr;
CreateIt(t);
try
{
    t->Size(100);
    t->Sin(v);                // OK: Vector converts to TVec* implicitly
}
catch (...)
{
    FreeIt(t);
    throw;
}
FreeIt(t);

3. Avoid element-by-element loops:

// BAD — slow, not vectorized
for (int i = 0; i < a.GetLength(); i++)
    a.Values(i) = std::sin(a.Values(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

In C++ the exceptions are thrown by value and derive from Dew::tException, whose Message field holds the text; catch them by const reference: catch (const EMtxVecException& e). A singular matrix is not an exception: LUSolve reports it through Infom->GetInfo() is non-zero — and leaves x unchanged, so check Info after the call.

// A matrix product requires A.Cols == B.Rows
try
{
    C.Mul(A, B);
}
catch (const EMtxVecException& e)
{
    std::printf("Mul failed: %s\n", e.Message.c_str());
}

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.