# Is there a way to capture an upper bound via dispatch?

**URL:** <https://discourse.julialang.org/t/is-there-a-way-to-capture-an-upper-bound-via-dispatch/63718>\
**Category:** General Usage\
**Created:** [June 28, 2021, 11:01pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-capture-an-upper-bound-via-dispatch/63718 "2021-06-28T23:01:30Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![marius311](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marius311/32/3953_2.png) [@marius311](https://discourse.julialang.org/u/marius311)\
**Post date:** [June 28, 2021, 11:01pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-capture-an-upper-bound-via-dispatch/63718/1 "2021-06-28T23:01:30Z")

</div>

As part of the logic of writing some function, I’d like to use the _upper bound_ of some passed-in type’s argument. Is there any way to capture this upper bound cleanly via dispatch? Basically, I’d like the following:

```julia
struct Foo{T<:Real} end

capture_upper_bound(Foo{Real}) # should return Real
capture_upper_bound(Foo{<:Real}) # should return Real
capture_upper_bound(Foo{<:Int}) # should return Int
capture_upper_bound(Foo{<:Number}) # should be a method error

```

The following definition of `capture_upper_bound` works, but the second method clearly is very hacky and not type stable and I wouldn’t really want to use it. Is there a better way to do this? Or is this one of those things that’s a lot more complex than seems at first glance and hence you can’t do with dispatch?

```julia
capture_upper_bound(::Type{F}) where {T<:Real, F<:Foo{T}} = T
capture_upper_bound(::Type{F}) where {T<:Real, F<:Foo{<:T}} = Base.unwrap_unionall(F).parameters[1].ub

```

---

<div class="post-metadata">

**Author:** ![benninkrs](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/benninkrs/32/3191_2.png) [@benninkrs](https://discourse.julialang.org/u/benninkrs)\
**Post date:** [June 29, 2021, 1:09am UTC](https://discourse.julialang.org/t/is-there-a-way-to-capture-an-upper-bound-via-dispatch/63718/2 "2021-06-29T01:09:47Z")

</div>

That’s about how I would’ve done it.

---

<div class="post-metadata">

**Author:** ![kimikage](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kimikage/32/14534_2.png) [@kimikage](https://discourse.julialang.org/u/kimikage)\
**Post date:** [June 29, 2021, 1:35am UTC](https://discourse.julialang.org/t/is-there-a-way-to-capture-an-upper-bound-via-dispatch/63718/3 "2021-06-29T01:35:02Z")

</div>

I’m using `@pure` to do constant folding on this, and that’s one of the things I want to avoid. 😕

---

<div class="post-metadata">

**Author:** ![marius311](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marius311/32/3953_2.png) [@marius311](https://discourse.julialang.org/u/marius311)\
**Post date:** [June 29, 2021, 2:28am UTC](https://discourse.julialang.org/t/is-there-a-way-to-capture-an-upper-bound-via-dispatch/63718/4 "2021-06-29T02:28:16Z")

</div>

Where exactly are you using `@pure`? In my case, this doesn’t seem to make it type stable (and I think technically breaks the purity rule since it calls several generic functions):

```julia
Base.@pure capture_upper_bound(::Type{F}) where {T<:Real, F<:Foo{<:T}} = Base.unwrap_unionall(F).parameters[1].ub

```

Fwiw, making it `@generated` does make it type stable, but still curious if there’s a way to do it with dispatch.

---

<div class="post-metadata">

**Author:** ![kimikage](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kimikage/32/14534_2.png) [@kimikage](https://discourse.julialang.org/u/kimikage)\
**Post date:** [June 29, 2021, 2:50am UTC](https://discourse.julialang.org/t/is-there-a-way-to-capture-an-upper-bound-via-dispatch/63718/5 "2021-06-29T02:50:50Z")

</div>

> <https://github.com/JuliaGraphics/ColorTypes.jl/blob/87364c41644c2fbea5aa7cb049cef15a4afb279f/src/traits.jl#L140-L142>

`@pure` only encourages constant folding, and it does not resolve the type instability of the callee itself. Also as you said, technically it is a misuse of `@pure`.

I have been struggling with this issue for almost a year now and have not found a good solution.

---

<div class="post-metadata">

**Author:** ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)\
**Post date:** [June 29, 2021, 8:02am UTC](https://discourse.julialang.org/t/is-there-a-way-to-capture-an-upper-bound-via-dispatch/63718/6 "2021-06-29T08:02:47Z")

</div>

Maybe I’m missing something here, because this seems very straightforward:

```julia
julia> struct Foo{T<:Real} end

julia> capture_upper_bound(::Type{<:Foo{<:Real}}) = Real
capture_upper_bound (generic function with 1 method)

julia> capture_upper_bound(::Type{<:Foo{<:Int}}) = Int
capture_upper_bound (generic function with 2 methods)

julia> capture_upper_bound(Foo{Real}) # should return Real
Real

julia> capture_upper_bound(Foo{<:Real}) # should return Real
Real

julia> capture_upper_bound(Foo{<:Int}) # should return Int
Int64

julia> capture_upper_bound(Foo{<:Number}) # should be a method error
ERROR: MethodError: no method matching capture_upper_bound(::Type{Foo{var"#s26"} where var"#s26"<:Number})
Closest candidates are:
  capture_upper_bound(::Type{var"#s26"} where var"#s26"<:(Foo{var"#s24"} where var"#s24"<:Int64)) at REPL[3]:1
  capture_upper_bound(::Type{var"#s24"} where var"#s24"<:(Foo{var"#s26"} where var"#s26"<:Real)) at REPL[2]:1
Stacktrace:
 [1] top-level scope
   @ REPL[7]:1

```

---

<div class="post-metadata">

**Author:** ![marius311](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marius311/32/3953_2.png) [@marius311](https://discourse.julialang.org/u/marius311)\
**Post date:** [June 29, 2021, 8:10am UTC](https://discourse.julialang.org/t/is-there-a-way-to-capture-an-upper-bound-via-dispatch/63718/7 "2021-06-29T08:10:35Z")

</div>

Yea, I should have said more explicitly, but I’m looking for a solution that doesn’t involve hard coding any of the upper bound possibilities, so would work with all existing types (AbstractFloat, Integer, etc… in this example), as well as ones defined in the future.
