# Surprising behaviour for arguments of different types

**URL:** <https://discourse.julialang.org/t/surprising-behaviour-for-arguments-of-different-types/18088>\
**Category:** General Usage\
**Created:** [November 28, 2018, 12:58am UTC](https://discourse.julialang.org/t/surprising-behaviour-for-arguments-of-different-types/18088 "2018-11-28T00:58:45Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [November 28, 2018, 12:58am UTC](https://discourse.julialang.org/t/surprising-behaviour-for-arguments-of-different-types/18088/1 "2018-11-28T00:58:45Z")

</div>

Suppose I want a function which takes varargs of any type, even different among arguments. Of course, there are two obvious ways to implement this:

```julia
f(x...) = typeof(x)
f(x::Vararg{Any}) = typeof(x)

```

Now I need to get the (most specific) type all arguments belong to, e.g. for `(5, 6)` I expect `Int`, for `(5, 6.0)` — `Real`, for `(5, nothing)` — `Union{Int, Nothing}` and so on. Before actually trying I was sure that replacing `Any` with `T` in the above example should do this, but

```julia
f(x::Vararg{T}) where {T} = typeof(x)

```

fails when its arguments do not have exactly the same type! E.g. `f(5, 6.0)` and `f(5, nothing)` say that no method matching. However, obviously, this method matches as there exists such `T` that both 5 and 6.0 are its instances.

The above happens for non-varargs as well.

So is there any way to work it around, i.e. get the most specific type all arguments belong to?

---

<div class="post-metadata">

**Author:** ![haberdashPI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/haberdashpi/32/26337_2.png) [@haberdashPI](https://discourse.julialang.org/u/haberdashPI)\
**Post date:** [November 28, 2018, 1:35am UTC](https://discourse.julialang.org/t/surprising-behaviour-for-arguments-of-different-types/18088/2 "2018-11-28T01:35:23Z")

</div>

When you specify a type parameter `T` across multiple arguments (implied by `Varargs{T}`), `T` must be concrete and it will need to be the _same_ concrete type. This is described [here](https://docs.julialang.org/en/v1/manual/methods/#Parametric-Methods-1) in the manual.

I don’t think your desire for a “most specific” type is well defined. For example `Union{A,B}` could be considered the most specific for any two arbitrary types `A` and `B`. Yet, you want `Real` for `(5, 6.0)` instead of `Union{Int,Float64}`. Note that `Union{Int,Float64} <: Real`.

That said, there may be a way to get what you want: I’m just not personally aware of what it is, and I think you will have to be more specific about what precisely you require. Why exactly do you need this most specific type? There is very little advantage to an abstract type like `Real` over just using `Any`.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [November 28, 2018, 1:46am UTC](https://discourse.julialang.org/t/surprising-behaviour-for-arguments-of-different-types/18088/3 "2018-11-28T01:46:56Z")

</div>

Ok, I see - didn’t notice that a parametrized type has to be concrete. Well, I didn’t have any particular example in mind where this could be used, it was a general question. But one possible case is when one wants two methods, one being called when there is at least one `nothing` among the arguments. Like `f(x::Vararg{T}) where {Nothing <: T} = nothing` — which doesn’t work of course.

---

<div class="post-metadata">

**Author:** ![haberdashPI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/haberdashpi/32/26337_2.png) [@haberdashPI](https://discourse.julialang.org/u/haberdashPI)\
**Post date:** [November 28, 2018, 2:01am UTC](https://discourse.julialang.org/t/surprising-behaviour-for-arguments-of-different-types/18088/4 "2018-11-28T02:01:13Z")

</div>

AFAIK I don’t think there’s an easy way to do that with parametric types.

In that particular example, I would personally just check for `x[i] isa Nothing` inside the method body. Because julia compiles a different version of the method for each set of concrete types, the `if` will be compiled away, and you’ll get an efficient implementation specific to types of the input.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [November 28, 2018, 2:32am UTC](https://discourse.julialang.org/t/surprising-behaviour-for-arguments-of-different-types/18088/5 "2018-11-28T02:32:11Z")

</div>

> [@aplavin](#):
>
> `f(x::Vararg{Any}) = typeof(x)`

Maybe you want `f(x::Vararg{<:Any}) = typeof(x)` … read about [invariance vs. covariance in the manual](https://docs.julialang.org/en/v1/manual/types/#Parametric-Composite-Types-1). However, `Vararg{Any}` also matches any tuple of types; maybe `Vararg` and `Tuple` types are a bit special…?

> Now I need to get the (most specific) type all arguments belong to

Perhaps you want `f(x...) = typejoin(map(typeof, x)...)`.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [November 28, 2018, 2:34am UTC](https://discourse.julialang.org/t/surprising-behaviour-for-arguments-of-different-types/18088/6 "2018-11-28T02:34:55Z")

</div>

I don’t see any difference between how these two variants (with `Any` and `<:Any`) perform.

And your second suggestion `f(x...) = typejoin(map(typeof, x)...)` gives `f(5, 6.0, nothing) == Any`. Btw, it seems completely equivalent to `f(x...) = eltype(x)`.
