How to design a custom array-like type for physics calculations: balancing functionality and customization?

I’m working on a project in physics where I need to create custom types that behave like arrays but don’t necessarily inherit from AbstractArray because I want to disable certain default functionalities. These types represent various mathematical entities in physics, such as lattices and metric tensors. I’m looking for guidance on how to design the interface for these types.

Here are the features I want to implement in these custom types:

  1. Indexing Interface: I want these types to support all the basic indexing operations like getindex and setindex.

  2. Equality based on Parent Type: Two instances of these types should be considered equal if and only if their parent types have the same name (not necessarily the same type) and the values they contain are semantically equal. For example, MyType{Int} and MyType{Float64} can be equal as long as their elements are equal. (See How to compare two vectors whose elements are equal but their types are not the same)

  3. Scalar Multiplication: When multiplying one of these types by a scalar, it should produce a new instance of the same type with the elements scaled by that scalar. For example, 1.0 * MyType{Int}(data) should yield a MyType{Float64}.

  4. Elementwise Addition and Subtraction: These types should support elementwise addition and subtraction, resulting in a new instance of the same type with elements added or subtracted accordingly.

  5. Scalar Division: These types should allow division by a scalar, but there might not always be an inverse operation.

  6. Matrix-Vector Multiplication and Linear Solve: I need these types to support matrix-vector multiplication and linear solve operations.

  7. Matrix-Matrix Multiplication: These types should also support matrix-matrix multiplication.

  8. No other LinearAlgebra operations: like transpose or det, etc.

  9. Fixed sizes: e.g. lattices are 3 \times 3 matrices, so are metric tensors.

I’m wondering if there’s an existing package that provides this kind of functionality or if not, what interface functions I should implement to achieve these features efficiently. Essentially, I’m looking for a design that combines elements of both an indexing interface and an array interface.
Thank you!

I think StaticArrays.jl has all of this, except point 8

You could build off that, perhaps.

This one was a bit weird, though,

because you are explicitly saying that the values play no part in equality (“if and only if”). But from your example I assume you didn’t mean that.

Sorry for the confusion, I mean their parent types’ name are the same and the values they contain are semantically equal. For example,

A{Int}(1, 2, 3) != B{Int}(1, 2, 3)
# but
A{Int}(1, 2, 3) == A{Float64}(1.0, 2.0, 3.0)