macro params(struct_expr)
name = struct_expr.args[2]
fields = @view struct_expr.args[3].args[2:2:end]
params = []
for i in 1:length(fields)
x = fields[i]
if x isa Symbol
T = gensym()
push!(params, T)
fields[i] = :($x::$T)
end
end
if name isa Symbol && length(params) > 0
struct_expr.args[2] = :($name{$(params...)})
elseif name.head == :curly
append!(struct_expr.args[2].args, params)
else
error("Unidentified type definition.")
end
esc(struct_expr)
end
julia> @params struct MyType
a
b::Int
c
end
julia> MyType{Int, Float64}(1, 1, 1.0)
MyType{Int64,Float64}(1, 1, 1.0)
I realize the above is not exactly the requested feature so…here you go:
macro params(struct_expr)
name = struct_expr.args[2]
fields = @view struct_expr.args[3].args[2:2:end]
params = []
for i in 1:length(fields)
x = fields[i]
T = gensym()
if x isa Symbol
push!(params, T)
fields[i] = :($x::$T)
elseif x.head == :(::)
abstr = x.args[2]
var = x.args[1]
push!(params, :($T <: $abstr))
fields[i] = :($var::$T)
end
end
if name isa Symbol && length(params) > 0
struct_expr.args[2] = :($name{$(params...)})
elseif name.head == :curly
append!(struct_expr.args[2].args, params)
else
error("Unidentified type definition.")
end
esc(struct_expr)
end
julia> @params struct MyType
a::Integer
b
end
julia> MyType(1,2)
MyType{Int64,Int64}(1, 2)
julia> MyType(1.0,2)
ERROR: MethodError: no method matching MyType(::Float64, ::Int64)
Closest candidates are:
MyType(::##360<:Integer, ::##361) where {##360<:Integer, ##361} at REPL[2]:2
Stacktrace:
[1] top-level scope at none:0
Do you need them at all? I usually end up deleting those qualifiers anyway once I realise I need to use a unit, not Real, or that a tuple would do instead of the Vector. Unless you really need the type checks.
Writing packages, I initially I went with safety and explicit type checks everywhere. But now I keep struct field types as loose as possible and give the user a little more rope to hang themselves with.
I’ve had a lot of hassles with overly restricted types blocking the use of Dual numbers or units in other peoples packages. Having to write a pull request to remove types is way more of a pain than not getting an immediate warning that you are using the wrong type. But opinions on this may vary.