I’m new to struct
and have found parametric types a bit difficult to understand. I would like to constrain the admissible types and fail gracefully with intelligible messages.
For instance, let’s say I only want to admit matrices of numbers. Here’s a first pass:
struct NumMatrix{T <: Number, S <: AbstractMatrix{T}}
A :: S
end
NumMatrix(["a" "b"; "c" "d"])
ERROR: MethodError: no method matching NumMatrix(::Matrix{String})
Closest candidates are:
NumMatrix(::S) where {T<:Number, S<:AbstractMatrix{T}} at REPL[1]:2
Did I get it right with the T
and S
?
Now I want to add a customized error message. If I use {T <: Number}
inside the type declarations, my error messages will get short cut, so I drop the <: Number
part:
struct NumMatrix{T, S <: AbstractMatrix{T}}
A :: S
function NumMatrix(A::S) where {T, S <: AbstractMatrix{T}}
if !(T <: Number)
throw(ErrorException("elements of matrix $A must of type Number, but instead are of type $T"))
end
new{T,S}(A)
end
end
NumMatrix(["a" "b"; "c" "d"])
ERROR: elements of matrix ["a" "b"; "c" "d"] must of type Number, but instead are of type String
Or with a more specific error handling (the matrix doesn’t print so pretty, but that’s fine):
struct TypeError <:Exception
msg :: String
end
struct NumMatrix{T <: Number, S <: AbstractMatrix{T}}
A :: S
function NumMatrix(A::S) where {T, S <: AbstractMatrix{T}}
if T <: Number
new{T,S}(A)
else
throw(TypeError("elements of matrix $A must be of type Number, but instead are of type $T"))
end
end
end
NumMatrix(["a" "b"; "c" "d"])
ERROR: TypeError("elements of matrix [\"a\" \"b\"; \"c\" \"d\"] must be of type Number, but instead are of type String")
Is this about right?
P.S. In a moment of madness, I also tried this:
struct NumMatrix{T <: Number || throw(ErrorException("No!")), S <: AbstractMatrix{T}}
but that isn’t allowed. Is there any way to throw error messages directly in the struct, without a method? Writing a method for it is fine, but having to re-state where {T, S <: AbstractMatrix{T}}
and write new{T,S}(A)
is a bit long-winded. Thanks.