Using type system for different coordinate systems?

I’m reasonably new to using Julia but I’ve been trying to rewrite a Fortran package in Julia. It mainly runs in a Cartesian-like coordinate system with very small sections that require some specialisation for different coordinate systems.
I was hoping to be write these small sections with multiply dispatched functions for each different coordinate system using the types of the vector field struct I’ve been using so far. Although looking through the documentation on types, I wasn’t entirely sure how to achieve it.

Right now, I have a struct containing containing various arrays which include the Vector Field and coordinates. One option seemed to be to have a different struct for each coordinate system:

struct CartesianField
    ...
end

struct SphericalField
   ...
end

and then have each of these to be a subtype of some AbstractField type.

Given I’m happy for each struct to have the same internal field names and could become very verbose for different coordinate systems, I wondered if I could use some sort of parametric type instead:

struct Field{T}
   ...
end

where T is the different coordinate system types. I noticed in one place in the documentation it seemed it might be possible to use Julia symbols for T (which I wasn’t sure why that worked) or perhaps different structs need to be created for each coordinate system which subtype some AbstractCoordinateSystem. What to use etc. is where I’m not sure. What might be best to go about this?

You can definitely have something like Field{:Cartesian}, Field{:Polar}, etc. I don’t think that’s the best way to go about this, though. The Field{T} approach means you cannot ever specialise the type based on the coordinate system. Also, the REPL and any decent editor allows you to type something like CartesianField using autocomplete, while Field{:Cartesian} would most likely not be auto-suggested. This might be a slightly silly argument, but it’s one thing which frequently annoyed me with Field{T}-type constructs.

1 Like

Thanks for you help, can you actually use any variable to parameterise a type? I think initially I thought that you could only use other types

Surprisingly, the documentation isn’t quite clear on this. I believe, the answer is that you can parametrise using types or any isbits value. Here’s an example:

julia> struct Foo{T}
           x::T
       end

julia> isbitstype(Foo{Int})
true

julia> Val(Foo(1)) 
Val{Foo{Int64}(1)}()

julia> isbitstype(Foo{String})
false

julia> Val(Foo("one"))
ERROR: TypeError: in Type, in parameter, expected Type, got Foo{String}
Stacktrace:
 [1] Val(::Foo{String}) at ./essentials.jl:698
 [2] top-level scope at REPL[11]:1

Being able to parametrise on values is useful e.g. for Julia’s Array{T,N} type. Here, T stands for the element type (e.g. Int or Float64), and N denotes the dimension of the array (e.g. Vector{T} == Array{T,1}, Matrix{T} == Array{T,2}).

cf https://docs.julialang.org/en/v1/manual/types/#man-types-1:

Both abstract and concrete types can be parameterized by other types. They can also be parameterized by symbols, by values of any type for which isbits returns true (essentially, things like numbers and bools that are stored like C types or struct s with no pointers to other objects), and also by tuples thereof. Type parameters may be omitted when they do not need to be referenced or restricted.

1 Like

Missed this, thanks for pointing it out.

Maybe it is worth mentioning this also in other parts of the documentation. I checked the “Parametric Types” and “Value Types” section and couldn’t find the precise list there.

If people agree, I can file a PR.

1 Like

Thanks for doing this! A PR would be great. I think that the list of things that can serve as type parameters

  1. should be moved to the Parametric Types section,

  2. written as an enumerated list for better visibility.

I am not very used to creating PRs, so please let me know if I messed something up.

1 Like