Let’s say I want to create a family of singleton types, and additional types that might use them as type parameters. The particular example I’m thinking of is a named Variable
type, and a type to hold powers of that variable:
struct Variable{Name}
Variable{N}() where {N} = new{typeassert(N, Symbol)}()
end
I have a choice here: I can either use the variable type as a parameter, or I can use its singleton instance. That is, I can do this:
struct Power{V <: Variable}
exponent::Int
end
or this:
struct Power{V}
exponent::Int
Power{V}(e::Int) where {V} = new{typeassert(V, Variable)}()
end
The first form seems cleaner and easier to write in this case. However, if I want to use a tuple of variables as parameters, I must use instances rather than types:
julia> struct Monomial{Vars}
exponents
end
julia> Monomial{(Variable{:x}, Variable{:y})}
ERROR: TypeError: Type: in parameter, expected Type, got Tuple{DataType,DataType}
julia> Monomial{(Variable{:x}(), Variable{:y}())}
Monomial{(Variable{:x}(), Variable{:y}())}
so for consistency with other types that might need a tuple of parameters, using instances seems preferable. Or perhaps it would be better to do Monomial{Tuple{Variable{:x}, Variable{:y}}}
?
My question is: are there other trade-offs that I haven’t brought up here?
For example, are there any efficiency differences between Power{Variable{:x}}
and Power{Variable{:x}()}
? Or have any of you tried structures like this, and did you form a clear preference? I imagine that the authors of packages like Unitful.jl have faced similar questions.
Thanks!