How to overload Base.Complex?

import Base: Complex

struct Complex{T}
    re::T
    im::T
end

gives

cannot assign a value to variable Base.Complex from module Main

Stacktrace:
 [1] top-level scope
   @ In[6]:1
 [2] eval
   @ .\boot.jl:360 [inlined]
 [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
   @ Base .\loading.jl:1116

Thanks.

You can overload functions, but there’s no concept of overloading concrete types.

What are you trying to do here? Maybe if you elaborate your intent, we can find another way.

Just want to define complex types over more general number types than real numbers, because the original definition in Base is

struct Complex{T <: Real}
    re::T
    im::T
end

Is there a new type of complex number that doesn’t fit this description from Wikipedia?

In mathematics, a complex number is an element of a number system that extends the real numbers with a specific element denoted i, called the imaginary unit and satisfying the equation i^{2}=-1; every complex number can be expressed in the form a+bi, where a and b are real numbers.

How if I want to have a complex over tuples of real numbers?

So if I understand you correctly, you have a tuple (a, b) representing a+bi, and would like it to become a Complex(a, b)?

If so:

julia> my_t = (1,2)
(1, 2)

julia> Complex(my_t...)
1 + 2im

The Complex constructor can be overloaded, allowing tuples to be passed directly into the constructor:

julia> Base.Complex(t::Tuple{Real,Real}) = Complex(t...)

julia> Complex(my_t)
1 + 2im

No. I mean I want to have something like

Complex(Tuple{Float,Float},Tuple{Float,Float})

What would the meaning of such a thing be?

Is each Tuple representing a single real number, for example by mantissa and exponent?

More precisely, what I want is

Complex(NTuple{N,Float},NTuple{N,Float})

Okay. So this is basically a representation for a sequence of complex numbers, if I understand correctly?

What’s the reason for not re-packaging these numbers into a Vector{ComplexF64}?

For performance reasons (like in StructArrays.jl, but want to have my own realization)

I think you mean StaticArrays.jl?

Is there a reason not to simply construct a tuple (or static array) of ComplexF64s, e.g. NTuple{N,ComplexF64}? Why split apart the real and imaginary components into separate sections of memory?

The main reason for using a Complex type is so that the arithmetic operations are defined. If you aren’t planning on using arithmetic, then the representation becomes more arbitrary.

Can you follow the same approach as StructArrays do? They don’t need to redefine any type like this.
Also, why don’t StructArrays work for you as-is? Using StaticArrays within StructArrays would give the same memory layout as the suggested tuple-in-complex type.

If you really want a complex-of-tuple type, just define it without importing from Base. It would be your own type that is free to change in arbitrary ways, and free to store anything inside.

2 Likes

You could have a look at Quaternions.jl. They contain 4 real values. It seems that you want to start from scratch for something new with 4 reals, and the Quaternions package can perhaps give some ideas, how to do this in Julia.

Thank you all, I will consider your suggestions.

Anyway, just curious about why struct cannot be overloaded, because even const can be overloaded

Structs are useful since the compiler can know how their data is best represented in memory (assuming they are type safe). If you could change the definition of a struct at any time then the compiler will have a hard time figuring this out. I think in theory it might be possible to change the definition of a struct (since you can also change a function definition), but it will probably make compilation slower.
By the way, constants cannot be “overloaded”, at least not in the way you want to change the struct, i.e. changing the type.

julia> const a = 1
1

julia> const a = "test"
ERROR: invalid redefinition of constant a
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1

1 Like

I think you’re confusing overloading with subtyping?

i.e. it sounds like you want a new subtype of Complex, but in Julia all concrete types are final for performance reasons (because it allows the compiler to specialize not only their memory layout but also to perform aggressive devirtualization / elimination of dynamic dispatch; this is also why C++ added a final keyword).

Of course, you are free to define your own type called Complex in your own module, but then it will be a completely distinct type that happens to share the same name, and won’t work with any functions or types that use Base.Complex.

1 Like

If I understand correctly, the optimization you want, is a ‘column-store’ of complex numbers i.e. a vector of complex numbers for which the memory layout has the real parts continuous in memory, and then the imaginary parts continuous in memory.

Is this the goal?

Yes, exactly, for simd optimization, just like StructArrays.jl.