# Apply function to tuple type parameters in a stable way

**URL:** <https://discourse.julialang.org/t/apply-function-to-tuple-type-parameters-in-a-stable-way/76335>\
**Category:** General Usage\
**Tags:** parametric-types, type-stability\
**Created:** [February 13, 2022, 9:21am UTC](https://discourse.julialang.org/t/apply-function-to-tuple-type-parameters-in-a-stable-way/76335 "2022-02-13T09:21:29Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![lostella](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lostella/32/356_2.png) [@lostella](https://discourse.julialang.org/u/lostella)\
**Post date:** [February 13, 2022, 9:21am UTC](https://discourse.julialang.org/t/apply-function-to-tuple-type-parameters-in-a-stable-way/76335/1 "2022-02-13T09:21:29Z")

</div>

I’d like to apply a function to all type parameters of _any given_ tuple type. I don’t know the size of the tuples, I would just like to accumulate the function over all type parameters. However, I cannot find a way to do this in an type inference-friendly way.

Here’s an example, I’m probably missing something obvious: right now I’m using the `parameters` attribute of a type.

```julia
myproperty(::Type) = false
myproperty(::Type{<:String}) = true
myproperty(::Type{<:Integer}) = true
myproperty(::Type{T}) where T <: Tuple = all(myproperty.(T.parameters))

myproperty(::T) where T = myproperty(T) # for convenience

myproperty((1, 2, 3)) # true
myproperty((1, 2, "ciao")) # true
myproperty((1, 2.7, "ciao")) # false

```

However, the following fails:

```julia
using Test
@inferred myproperty((1, 2.7, "ciao"))
# ERROR: return type Bool does not match inferred return type Union{Missing, Bool}

```

If I check what the `parameters` attribute is, I understand that this is a `SimpleVector`:

```julia
julia> typeof((1, 2.7, "ciao")).parameters
svec(Int64, Float64, String)

```

Any way one could get a `Tuple` of the type parameters, so that what I’m trying to do above is type-stable?

Edit: even using `fieldtypes` as follows doesn’t seem to fix this

```julia
myproperty(::Type{T}) where T <: Tuple = all(myproperty.(fieldtypes(T)))

```

---

<div class="post-metadata">

**Author:** ![DrChainsaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drchainsaw/32/8497_2.png) [@DrChainsaw](https://discourse.julialang.org/u/DrChainsaw)\
**Post date:** [February 13, 2022, 10:19am UTC](https://discourse.julialang.org/t/apply-function-to-tuple-type-parameters-in-a-stable-way/76335/2 "2022-02-13T10:19:08Z")

</div>

Hipshot from phone: Doesn’t `all` return missing in some cases, e.g if input is empty or missing?

---

<div class="post-metadata">

**Author:** ![lostella](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lostella/32/356_2.png) [@lostella](https://discourse.julialang.org/u/lostella)\
**Post date:** [February 13, 2022, 10:44am UTC](https://discourse.julialang.org/t/apply-function-to-tuple-type-parameters-in-a-stable-way/76335/3 "2022-02-13T10:44:54Z")

</div>

Also from phone: good call, that might be it. If so, I’ll have to guard against empty tuple types somehow.

---

<div class="post-metadata">

**Author:** ![lostella](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lostella/32/356_2.png) [@lostella](https://discourse.julialang.org/u/lostella)\
**Post date:** [February 13, 2022, 12:20pm UTC](https://discourse.julialang.org/t/apply-function-to-tuple-type-parameters-in-a-stable-way/76335/4 "2022-02-13T12:20:48Z")

</div>

Actually no, it seems like it returns `true` on empty collections.

---

<div class="post-metadata">

**Author:** ![tlienart](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tlienart/32/7640_2.png) [@tlienart](https://discourse.julialang.org/u/tlienart)\
**Post date:** [February 13, 2022, 1:32pm UTC](https://discourse.julialang.org/t/apply-function-to-tuple-type-parameters-in-a-stable-way/76335/5 "2022-02-13T13:32:07Z")

</div>

I think what @DrChainsaw is hinting at is more if you have a `missing` inside the collection (not sure whether that would ever happen in your case though):

```julia
julia> all(x -> x < 10, [1, 2, missing])
missing

```

Additional note that `all(my property, T.parameters)` is probably preferable (lazy?).

---

<div class="post-metadata">

**Author:** ![tlienart](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tlienart/32/7640_2.png) [@tlienart](https://discourse.julialang.org/u/tlienart)\
**Post date:** [February 13, 2022, 1:38pm UTC](https://discourse.julialang.org/t/apply-function-to-tuple-type-parameters-in-a-stable-way/76335/6 "2022-02-13T13:38:33Z")

</div>

How about this? (apologies for the 2x post)

```julia
myproperty(::Type{T}) where T = false
myproperty(::Type{<:Union{String, Integer}}) = true
myproperty(::T) where T = myproperty(T)
myproperty(::Type{T}) where T <: Tuple = 
  any(ismissing, T.parameters) ? false : all(myproperty, T.parameters)::Bool

```

```julia
julia> using Test

julia> @inferred myproperty((1, 2.7, "ciao"))
false

julia> @inferred myproperty((1, 2.7, "ciao", missing))
false

julia> @inferred myproperty((1, 2, "ciao", missing))
false

julia> @inferred myproperty((1, 2, "ciao"))
true

```

---

<div class="post-metadata">

**Author:** ![lostella](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lostella/32/356_2.png) [@lostella](https://discourse.julialang.org/u/lostella)\
**Post date:** [February 13, 2022, 3:26pm UTC](https://discourse.julialang.org/t/apply-function-to-tuple-type-parameters-in-a-stable-way/76335/7 "2022-02-13T15:26:50Z")

</div>

That does it, thank you!

In my example `missing` should not be a problem, since all elements that go through `myproperty` are either a `Type`, or get turned into their own type. So in the end `myproperty` can only result in a `Bool`. In fact

```julia
myproperty(missing) == myproperty(Missing) == false

```

For some reason the compiler doesn’t get this, so it’s the `::Bool` annotation that really solves my issues here. Maybe the additional safeguard is not needed?

(However good point @tlienart about lazily applying `myproperty`, thanks!)

---

<div class="post-metadata">

**Author:** ![tlienart](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tlienart/32/7640_2.png) [@tlienart](https://discourse.julialang.org/u/tlienart)\
**Post date:** [February 13, 2022, 3:32pm UTC](https://discourse.julialang.org/t/apply-function-to-tuple-type-parameters-in-a-stable-way/76335/8 "2022-02-13T15:32:54Z")

</div>

I _think_ the problem may be with `all` then (and through it, `reducedim`); not sure if these functions can generally be type stable given they work on collections which can be anything. In your case, though if you know for sure that there’s no missing case, why not remove the branch and just do

```julia
myproperty(::Type{T}) where T <: Tuple = all(myproperty, T.parameters)::Bool

```

this will error if at runtime any of the parameter is missing but should be type stable (I think).
