Re-implementing old wheels

The mathematics used by engineers is “advanced” compared to high school, but engineering math is still rather tame compared to modern mathematical research (e.g., moonshine theory). For this reason, engineering math is rather old, and the mathematical nomenclature in an engineer’s references are extremely standardized (e.g., integrals and algebra look alike). Some differences may exist between locales (e.g., the comma/period as numeric delimiter in the US vs. Europe), and sometimes there is no clear convention (e.g., the best way to typeset vectors), but usually the differences are subtle and easy to swap by-eye.

But when an engineer needs to implement standardized math in code they enter a world a pain. A world of pain! Because in every single programming language the math looks and feels differently. Not just style choices, substantial differences. Furthermore, most languages provide almost nothing besides scalar math, so linear algebra is usually a 3rd-party library (e.g., an open-source). And when computer languages are based around math (e.g., MATLAB, Mathematica), they tend to be private (requiring a subscription). Engineers are often forced to re-implement old wheels because something was prototyped in MATLAB and now needs to be implemented in Java. I have used Apache Commons to solve many math problems in Java, and have found Apache to have substantially worse numerical stability than MATLAB.

Is the solution another programming language? Not likely! An xkcd comic from 2011 neatly explains. This is ancient wisdom codified over 2000 years ago in the Art of War. Master Sun defined nine grounds, of which one is the “ground of contention” — land that is advantageous to all. Master Sun advises to never attack the ground of contention (i.e., get there first or forget about it). Adding a new coding language to an existing pile is attacking the ground of contention, so I propose to attack an empty pile.

One World Language (OWL) is an interface

The golden nugget of OWL is simple: “Instead of unifying math with one programming language, define one unified interface that can be implemented in each programming language.” For example, if a Matrix can operate on a Vector, then the Matrix interface might resemble

public interface Matrix
   extends Tensor<Matrix>
{
   ...
   operate(Vector) -> [Vector]
   operate(Matrix) -> [Matrix]
   ...
}

public interface Tensor<T extends Tensor<T>>
   extends Numeric
{
   ...
   scale(Scalar) -> [T]
   ...
}

Most of the Matrix interface is hidden, but we show its most used functions. The inputs and outputs are anonymous (not-named) because their identity is obvious from the name of the function. The Matrix interface extends the Tensor interface because a matrix is one kind of tensor, and any tensor can be scaled by a scalar — why define scaling seperately in every interface that extends Tensor? The unfortunate consequence of forcing all Tensors to share the “scale” function is the curiously recurring template pattern.

With the OWL interface, math should feel the same in every language because objects and functions will have the same names, arguments, and return values. OWL has no implementation, very much like the C++ Standard Template Library, so implementing OWL in each language remains a one-time chore (and may require some hacking or concessions). But today’s status quo is constantly re-implementing old wheels, so OWL sounds like an overdue chore!

IEEE754 was an important first step towards standardizing floating-point arithmetic, but humanity has yet to standardize floating-point math. With the OWL interface, we can finally speak math with One World Language!

OWL Interface Plan

I have spent a little time sketching out some pseudo-code, and the following plan sounds possible. OWL is a set of interfaces that obey rules.

OWL’s interfaces are like Java 8 interfaces; interfaces define a set of functions one can call, but without any implementation. Interfaces are very useful for defining an algorithm without choosing an implementation. Hidden behavior (that not specified in the interface) can be completely redesigned and the end-user is none the wiser. Java avoids the diamond problem (common to polymorphism) by restricting a class to extend only one superclass, then allowing it to implement as many interfaces as it wants. Incidentally, “extend one implement many” solves many problems of the Liskov subsitution principle, because the interfaces maintain the contracts upon substitution.

OWL forces its interfaces to obey rules. Rules define things like syntax, order of operations, and rules about function input/output (e.g., named arguments). This keeps all assumptions on the table and forces some compliance. We expect most interfaces to use the SAFE_LAW, the basic rules of OWL. Thus, OWL users will not write rules often, but they will need to understand rules to follow them.

One rule that keeps OWL safe is NAMED_NOLIMIT: “Unlimited named arguments and unlimited named return values”. Named return values can be unpacked into a dictionary (similar to MATLAB, but with strong assignment):

// Define foo
foo(Vector a) -> [Matrix *, Vector meta]
{
   return a.outer(a), a;
}

// Call the function
main()
{
   Vector a = Vector.randn(3);
   Matrix b, {'meta': a} = foo(a);
   a = foo(a); // named returns discarded
}

When using multiple return, the position arguments are un-packed first, followed by the named returns (via a Python-like dictionary mapping symbolic names to the assigned reference). Like MATLAB and python, extra returns can be ignored.

NAMED_NOLIMIT combines ideas from Python3 and MATLAB. The rule-set of OWL is defined by composition. The rules constraints the interface (and its sub-interfaces) in service of several goals:

  • Define and enforce coding best-practices for safety (e.g., NAMED_NOLIMIT helps avoid positional arguments, lest they be used in the wrong order). Rules “chunk” various style choices for debate, aiming for uniformity throughout OWL while permitting some specialization within distinct subjects.

  • Mix-and-match the best features from each programming languages. As of 2024, no language does math perfectly. Since OWL is not a programming language, it can aspire to impossible code patterns and define acceptable substitutes (until languages get up-to-speed).

  • Adopt a “big tent” approach whenever there is unbreakable factionalism (e.g., “do indices start counting from 0 or 1?”). Why not give the user the option to use either? The rule ZERO_OR_ONE would establish such rules (e.g., “An enum is passed via the named argument ‘idx_domain’. If absent, an exception is thrown unless a global default has been explicitly chosen with a prior static function call”.

Rules will almost certainly be English words describing what the rule should do. For the purposes of writing interfaces, human readability is superior to numerical completeness. Enforcing rules will require similar parsing and text-validation schemes as a compiler. Rules may even require manual verification, like traditional engineering requirements.

On intersecting ground, form communications

OWL is currently a pipe dream. I need your help! What am I missing? Does this already exist? Please reach out via the Contacts pane, so we can collaborate.

Comment

$\setCounter{0}$