# defined parametric type is abstract, an iterated union
# of parametric concrete types with specific parameter values
# e.g. A{1}, A{:hello}, A{Int}
struct A{T}
end
# calls with arguments of type A may be dispatched to this method
func(a::A) = #code
# this is not valid Julia code, throws syntax error on attempt
func(a<:A) = #code
# arguments of type A, but the method is parameterized by T.
# T is available as a variable in the method body and shared with
# the parameter of an argument type a::A{T}.
# The function call must provide a known T value to dispatch to this.
# Parameters are the go-to way of using compile-time information,
# since methods are compiled on type signatures.
func(a::A{T}) where {T} = #code
# not valid code, same error
func(a<:A{T}) where {T} = #code
# the instance of Type{A} is A, so the only argument you can pass is A
# not any concrete subtypes with specified parameters, only A
func(a::Type{A}) = #code
# Type{<:A} is shorthand for (Type{S} where S<:A)
# So any subtype of A, including A itself, is accepted.
# This is not a parametric method because the method itself does not
# have a parameter, only an argument type.
func(a::Type{<:A}) = #code
Oh, probably worth mentioning this too, <: goes in where clauses of definitions, which is probably what you need to know to avoid those syntax errors. This is treated differently from the <: binary operator you can call in running code.
# V this serves as where clause for struct, despite lack of where
struct A{T}
end
# V no V yes for method
func(a::A{T}) where {T} = # code
# V yes for type, shorthand form
func(a::Type{<:A}) = # code
# V yes for type, full form
func(a::Type{S} where {S<:A}) = # code