# Tuple{Vararg{T, N}} where N \>= 1

**URL:** <https://discourse.julialang.org/t/tuple-vararg-t-n-where-n-1/121644>\
**Category:** General Usage\
**Tags:** question, type, tuple\
**Created:** [October 23, 2024, 1:58pm UTC](https://discourse.julialang.org/t/tuple-vararg-t-n-where-n-1/121644 "2024-10-23T13:58:22Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![croberts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/croberts/32/9465_2.png) [@croberts](https://discourse.julialang.org/u/croberts)\
**Post date:** [October 23, 2024, 1:58pm UTC](https://discourse.julialang.org/t/tuple-vararg-t-n-where-n-1/121644/1 "2024-10-23T13:58:22Z")

</div>

It can be extremely convenient to dispatch on the types of arguments in a tuple, creating an alias for tuples of a type. However, a zero-length tuple will match a Vararg Tuple of any type, which can create issues with dispatch and type piracy. How can I impose the restriction that the vararg tuple have at least one element?

MWE:

```julia
abstract type AbstractMyType end 
struct MyType <: AbstractMyType  
    x
end 

const InformalGroupedType = Tuple{Vararg{AbstractMyType}}

do_something(arg::InformalGroupedType) = println("did something") 

my_informal_grouped_type = 1:3 .|> MyType |> Tuple 

do_something(my_informal_grouped_type) 

```

Unfortunately, a zero-length tuple can match the above alias

```julia
typeof(Tuple(){}) <: InformalGroupedType # evaluates to true 

```

Is there any way to impose the restriction

```julia
# this is not syntactically valid. Is there a syntax for this idea? 
const InformalGroupedType = Tuple{Vararg{AbstractMyType, N}} where N >= 1 

```

?

This is causing me problems when I extend the `show` function to my analogue of InformalGroupedType.  
The big problem here is that dispatching an existing function on a Tuple{Vararg{T}} is implicitly type piracy even if T is a type I created. So, unless there is a way to restrict the Vararg to length greater than 0, one ought never extend existing functions to Vararg tuples of user defined type, which would be disappointing.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [October 23, 2024, 2:08pm UTC](https://discourse.julialang.org/t/tuple-vararg-t-n-where-n-1/121644/2 "2024-10-23T14:08:07Z")

</div>

> [@croberts](#):
>
> How can I impose the restriction that the vararg tuple have at least one element?

You cannot - define a method that takes one argument, as well as the `Vararg`.

> [@croberts](#):
>
> Is there a syntax for this idea?

Not at the moment, no. There are various versions of this idea and lots of people look for something like this (most often in the context of “some type parameter must be in some range of values”). You’ll probably find some threads about this here already.

---

<div class="post-metadata">

**Author:** ![croberts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/croberts/32/9465_2.png) [@croberts](https://discourse.julialang.org/u/croberts)\
**Post date:** [October 23, 2024, 2:11pm UTC](https://discourse.julialang.org/t/tuple-vararg-t-n-where-n-1/121644/3 "2024-10-23T14:11:35Z")

</div>

Thanks for the information, and that’s too bad.

Aliasing Vararg Tuples of my type and dispatching on the alias is too convenient for me to stop using it, but I will have to be careful that implicit type piracy does not cause problems.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [October 23, 2024, 2:14pm UTC](https://discourse.julialang.org/t/tuple-vararg-t-n-where-n-1/121644/4 "2024-10-23T14:14:24Z")

</div>

> [@croberts](#):
>
> Is there any way to impose the restriction
> 
> ```julia
> # this is not syntactically valid. Is there a syntax for this idea? 
> const InformalGroupedType = Tuple{Vararg{AbstractMyType, N}} where N >= 1 
> 
> ```
> 
> ?

Sure:

```julia
const InformalGroupedType = Tuple{AbstractMyType, Vararg{AbstractMyType}}

```

---

<div class="post-metadata">

**Author:** ![croberts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/croberts/32/9465_2.png) [@croberts](https://discourse.julialang.org/u/croberts)\
**Post date:** [October 23, 2024, 2:17pm UTC](https://discourse.julialang.org/t/tuple-vararg-t-n-where-n-1/121644/5 "2024-10-23T14:17:45Z")

</div>

Your answer is correct, prior answer was wrong.

~~Prior response has it right.  
There is currently no way to impose that Vararg is nonzero, so `typeof(Tuple{}()) <: Tuple{Vararg{T}} where T <: WhateverType`  
for any type WhateverType, which means writing methods of existing functions on a vararg tuple type is implicitly type piracy~~

---

<div class="post-metadata">

**Author:** ![croberts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/croberts/32/9465_2.png) [@croberts](https://discourse.julialang.org/u/croberts)\
**Post date:** [October 23, 2024, 6:03pm UTC](https://discourse.julialang.org/t/tuple-vararg-t-n-where-n-1/121644/8 "2024-10-23T18:03:19Z")

</div>

> [@nsajko](#):
>
> `const InformalGroupedType = Tuple{AbstractMyType, Vararg{AbstractMyType}}`

I am an idiot, I misread your answers as simply dropping the N from the Vararg argument. Your answer is correct, the previous answer was incorrect. Thank you.

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [October 23, 2024, 6:06pm UTC](https://discourse.julialang.org/t/tuple-vararg-t-n-where-n-1/121644/9 "2024-10-23T18:06:32Z")

</div>

> [@croberts](#):
>
> The big problem here is that dispatching an existing function on a Tuple{Vararg{T}} is implicitly type piracy even if T is a type I created. So, unless there is a way to restrict the Vararg to length greater than 0, one ought never extend existing functions to Vararg tuples of user defined type, which would be disappointing.

I’m probably missing something obvious, but why would this restriction solve your type piracy issue?

---

<div class="post-metadata">

**Author:** ![brainandforce](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brainandforce/32/211054_2.png) [@brainandforce](https://discourse.julialang.org/u/brainandforce)\
**Post date:** [October 23, 2024, 6:49pm UTC](https://discourse.julialang.org/t/tuple-vararg-t-n-where-n-1/121644/10 "2024-10-23T18:49:25Z")

</div>

> [@eldee](#):
>
> I’m probably missing something obvious, but why would this restriction solve your type piracy issue?

Even if you own type `T`, `Tuple{Vararg{T}}` includes the empty tuple type `Tuple{}`, which is not a type owned by the package that provides type `T`. `Vararg{T}` represents _zero or more_ instances of type `T`.

If an already existing function from a different package, `f`, doesn’t have a method with signature `f(::Tuple{})`, then a package providing a method `f(::Tuple{Vararg{T}})` would implicitly define it for `Tuple{}` arguments.

The solution is to dispatch on `Tuple{T, Vararg{T}}` because it guarantees at least one element of type `T` is present in the tuple and is therefore never empty.

Methods like this can also be the source of method ambiguities, so it’s useful to use this construct in various places.

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [October 23, 2024, 7:03pm UTC](https://discourse.julialang.org/t/tuple-vararg-t-n-where-n-1/121644/11 "2024-10-23T19:03:52Z")

</div>

I hope I understand your question. Forgive me if I don’t.

_EDIT: and the above poster beat me to it, but I’ll dogpile my answer here just in case it helps someone see more clearly._

An example of the issue is that `Base.:+(::Vararg{MyType})` matches

```julia
Base.:+() # this is piracy! MyType is not involved!
Base.:+(::MyType)
Base.:+(::MyType, ::MyType)
Base.:+(::MyType, ::MyType, ::MyType)
# etc

```

whereas the definition `Base.:+(::MyType, ::Vararg{MyType})` would match all of these _except_ the problematic `Base.:+()`.

The same thing happens with `Tuple{Vararg}`. `() isa Tuple{Vararg{MyType}}` and also `() isa Tuple{Vararg{AnyOtherType}}`. It’s ambiguous what the `eltype` of an empty `Tuple` should be.

So the takeaway is that a purely-`Vararg` argument/tuple (or `NTuple{N} where N` if `N` could be 0) does not actually provide the disambiguation required to avoid piracy. You need another identifiable argument to the method/tuple to prevent accidental piracy in the empty case.

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [October 23, 2024, 7:35pm UTC](https://discourse.julialang.org/t/tuple-vararg-t-n-where-n-1/121644/12 "2024-10-23T19:35:39Z")

</div>

Thanks for the explanation, @brainandforce and @mikmoore! I’m pretty sure I now better understand the point @croberts was making.

> [@brainandforce](#):
>
> Methods like this can also be the source of method ambiguities, so it’s useful to use this construct in various places.

It seems Julia has some built-in safety for `Vararg{T, N}` when `N == 0` as it is indeed inherently ambiguous about `T`. (Edit: see also the [documentation](https://docs.julialang.org/en/v1/manual/methods/#Tuple-and-NTuple-arguments).)

```julia-repl
julia> f(a::Vararg{Int}) = 1
f (generic function with 1 method)

julia> f(a::Vararg{Float64}) = 2
f (generic function with 2 methods)

julia> f()
ERROR: MethodError: f() is ambiguous.

Candidates:
  f(a::Float64...)
    @ Main REPL[2]:1
  f(a::Int64...)
    @ Main REPL[1]:1

Possible fix, define
  f()

```

But I struggle to see how this would lead to type piracy (unless you forcefully define `f()` “for your own type `T`”). Also, the only situation I can imagine the ambiguity manifesting naturally is when splatting a `Tuple{T}` which turns out to be empty.

```julia-repl
julia> function g(x) # ::Tuple{Int} but not explicitly as !( () isa Tuple{Int})
           if x > 0
               return (1, 2)
           elseif x < 0
               return (3)
           else
               return ()
           end
       end
g (generic function with 1 method)

julia> f(g(1)...)
1

julia> f(g(0)...)
ERROR: MethodError: f() is ambiguous.

```

* * *

(Edit: In the previous posts we’re using `Tuple{Vararg{T}}` instead of just `Vararg{T}`, but I don’t think this matters.)
