ArrFuncs + Flags

Slots on the dtype (in some form or another), seems straight forward,
they need to return some wrapped C function (which could call back to python).

Need to think about what to do with kind and type (they cannot be
just chars I think, not for extension types).

Casting

  • Check if casting is possible:
    • "unsafe" is always true currently
    • "safe" is registered or assumed for same kind, byteorder, and itemsize
    • "same-kind": Internal ordering of types.
  • Register casting functions (via API).
    • Allows discovering easier what casting options exist?
    • More performant?
    • Current implementation (but special rules baked in for scalars)
  • Ask both dtypes involved if they know how to the casting under the given
    rule.
    • More like a typical python operator (or numpy dispatcher).
    • Should it be cached? (but not for value based scalars?)
  • Are casts between identical types always possible?
    • If yes: means that units must create new dtype's for each unit.

"Python" casting:

  • Need to define getitem and setitem casts to/from python objects.
    (can probably be simple slots)

Promotion

  1. np.result_type → finding common type
    • Current implementation:
      • Goes through PyArray_PromoteTypes to promote pairs:
        • Baked in for typical types
        • Checks "safe" casting in both directions (first argument checked first)
      • Scalar/same-kind logic fairly baked in.
    • Could be a __promote__(type1, type2) or __promote__(*types)?
    • Should have subclass priority logic (similar to __array_ufunc__)
  2. Dtype discovery for np.array
    • Currently:
      • Uses type promotion on pairs (safe casting)
      • Recognizes generic scalar subclasses and array-like protocols.
  3. Promote Flexible Types (currently all baked in)!
  4. Ufunc specific promotion.

UFuncs

  1. Resolve __array_ufunc__ for the container types.

    • The container type must be able to do the steps below as well probably.
    • (xnd has different kernels, strided, contiguous, ragged should we
      anticipate such a thing?)
  2. Interact with ufunc object to get and check signature information such as:

    • Correct shapes (gufuncs)
    • Correct input and output arguments
    • Possibly parameter type kwarg?
  3. Prepare the actual iteration:

    • Find the actual loop being used:
      1. Type promotion may be necessary (who does it?)
      2. Input and output datatypes have to be set.
      3. inner-loop function needs to be found.
      4. Flexible output dtypes may need to be fixed/modified.
      5. Get correct identity if it exists.
    • If necessary, prepare any casting of input and output variables:
      • Casting rules are defined during ufunc call
      • Could allow changing casting rules (or enforcing them elsewhere).
  4. Run any dtypes/ufunc-loop specific setup code

    • (Things in 3. and 4. may happen in different order)
    • Decide whether to force to use the Py-API or not
    • Possibly decide other flags iteration parameters (expandable, like iteration order)?
    • Do any setup/metadata the inner-loop function requires.
  5. Run the loop (allow early finishing)

  6. Run dtypes/ufunc-loop specific teardown code.

Type Hierarchy and Flexible Types

  • Are units flexible metadata or each their own type?
  • Types such as floating should work much like a flexible type?
    (currently, np.dtype(np.floating) == "float64", but it would be nice if it
    was actually any floating point with default 64bit).
Select a repo