a would accept vector of real numbers, such as Vector{Int64}, Vector{Float64}, ... b should be Integer while elements of a are Integers, and Integer or Float while elements of a are Floats.
Here is a type constrained version
function foo(a::Vector{T},b::T) where {T<:Real}
...
end
The problem of this version is that the Integer is not a subtype of AbstractFloat, so that
foo([1,2,3], 5) is allowed, and foo([1.0,2.0,3.0], 5) is not allowed, but foo([1.0,2.0,3.0], 5.0) is ok.
How can i constrain the type parameters so that the desired behavior (last two invoke) be achieved in one method definition, or is it possible to do at all?
foo(a::Vector{<:Real},b::Real) will make
foo([1,2,3], 5.0) allowed, but is not the desired behavior
The function would be an algorithm for discrete and continues domains, so when a is represented in discrete integers, b should also be integer, on the other hand, if a is floating points, it doesn’t matter b in float or integer. The original type constrained version force b be the same floating point type.
For the cases you want to throw (e.g. vector of integers with floating point b), I would add a check that throws with a helpful error message, or define a method that this case hits to throw a helpful error message.
If the types are known at compile time (i.e. the call to foo is typestable), this would have 0 runtime overhead in the cases you support.
If you’d prefer a MethodError, and you’re also handling all the cases you do support with the same implementation, then you can make that implementation an unconstrained _foo, and have a foo for each case that you do support forward there.
I’d do what is simplest (so long as they have 0 runtime overhead, which is the case for all proposals here), which depends on what foo’s implementation looks like.
Like if you need different implementations on input types, it’d make sense to just define those directly, and not define the type combinations you don’t support.