What exactly is a `Number`?

Suppose I want to implement some “numbers” (which should at least be a ring in the mathematical sense) in Julia. The documentation says that Number is the abstract supertype for all number types. Does Julia put any assumptions on elements of type Number that are needed for some functions accepting number to work correctly? For example, does the ring have to be commutative, or of characteristic zero? Or are users not supposed to define new subtypes of Number?

1 Like

A practical example: https://discourse.julialang.org/t/taking-quaternions-seriously/

This example suggest that Numbers need not have a commutative product. But it’s still unclear to me what the general assumptions are. Would (non-associative) octonions also be allowed? What about modular arithmetic? The integers mod n have positive characteristic and also zero-divisors unless n is prime. Will functions accepting Number arguments work with these kind of numbers?

There are no guarantees. Some methods accepting Number might require only + and non-commutative * (and related functions like zero and one). Some methods might expect not only /, but even functions like exp or sqrt. Some methods might in principle work for non-commutative *, but in practice they’ve only been tested for commutative * and so will give wrong results in a non-commutative algebra like quaternions.

In practice, people implement all sorts of number-like types (quaternions, octonions, Galois fields, …), try to use them with as many functions as they can, and either implement new methods or submit patches in cases where existing methods fall down but a corresponding function exists for that number type. (A nice thing about Julia is that you can easily extend functions from other packages by implementing new methods for your type in your package.)

5 Likes

I agree that it’s nice to be able to extend or modify functions from other packages. But I also think it would be very helpful if it were clear what functionality I have to provide if I want to implement a subtype of a given abstract type (in this case, Number). I don’t want to start a general discussion about interfaces (traits, …) here, but it seems to me that this aspect is very much worth thinking about.

Is it completely out of question having these functions implemented in pure Julia such that the extension of more basic operations made them work as well?

@matthias314 just make sure that you are not reinventing the wheel. I am positive that there are tons of high-level packages for abstract algebra out there where you can customize the operations and let the package do the heavy lifting for you.

exp is in pure Julia. The problem is that the method to compute exp (and similar functions) depends heavily on how the number is represented. (For example, the Float64 exp involves reinterpreting the memory as an unsigned integer at one point). Also, some objects like finite fields don’t have exponentials, but are arguably numbers.

1 Like

I’d say that one of the only things that one really expects from a number is that they behave immutably and usually are implemented with an immutable type. This is because mathematical objects in general are immutable and identified by value. You cannot change the value of an integer, you can only change the value that an integer variable refers to. Of course in practice BigInts and BigFloats have to be heap allocated and can be mutated but you should be very careful to avoid making that mutation observable outside of the implementation of some function. Similarly vectors and matrices and so on are immutable mathematically but for performance reasons are mutable. It would be lovely to get to a place where we can have immutable semantics for mathematical arrays and rely on the compiler being good enough at eliminating mutation to emit the efficient code.

Otherwise, as @stevengj said, there’s not much that one can insist on all numbers doing, which is why there isn’t really any Number interface. The type exists to provide fallback behaviors that tend to be useful for numeric types, such as “automatic” promotion for numerical operations (ie default methods for arithmetic operators fall back to promotion for numbers). If you want that to work you still need to define promote rules and conversions but then you get numerical promotion where expected. For Any type nothing automatic like that is defined, you have to impeller it yourself.