# Why are returned types different in comprehension over an empty range if called from a function vs top level?

**URL:** <https://discourse.julialang.org/t/why-are-returned-types-different-in-comprehension-over-an-empty-range-if-called-from-a-function-vs-top-level/103533>\
**Category:** General Usage\
**Tags:** parametric-types, type-stability, comprehension\
**Created:** [September 5, 2023, 7:02am UTC](https://discourse.julialang.org/t/why-are-returned-types-different-in-comprehension-over-an-empty-range-if-called-from-a-function-vs-top-level/103533 "2023-09-05T07:02:26Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [September 5, 2023, 7:02am UTC](https://discourse.julialang.org/t/why-are-returned-types-different-in-comprehension-over-an-empty-range-if-called-from-a-function-vs-top-level/103533/1 "2023-09-05T07:02:26Z")

</div>

```julia
julia> using ApproxFun

julia> rs = Jacobi(5,4);

julia> d = domain(rs);

julia> Sf = JacobiWeight(0,2,ConstantSpace(d));

julia> using ApproxFun.ApproxFunSingularities: jacobiweight

julia> using ApproxFun.ApproxFunBase: ConcreteMultiplication

julia> min(rs.b, Sf.β)-1:-1:1 # empty range
-1:-1:0

julia> [ConcreteMultiplication(jacobiweight(1,0,d), Jacobi(rs.b-i,rs.a,d)) for i in min(rs.b, Sf.β)-1:-1:1]
Any[]

julia> ((rs,Sf,d) -> [ConcreteMultiplication(jacobiweight(1,0,d), Jacobi(rs.b-i,rs.a,d)) for i in min(rs.b, Sf.β)-1:-1:1])(rs,Sf,d)
ConcreteMultiplication{JacobiWeight{ConstantSpace{ChebyshevInterval{Float64}, Float64}, ChebyshevInterval{Float64}, Float64, Int64}, Jacobi{ChebyshevInterval{Float64}, Float64, Int64}, Float64}[]

julia> VERSION
v"1.9.3"

```

Why are the types different? The second call is identical to the first, except this time this is placed in a function. My impression was that this might help with type-inference, but won’t change the actual types that are returned.

Edit: On second thought, perhaps the inferred type (using `@default_eltype`) is used to allocate the container, which is a bit unfortunate

```julia
julia> G =(ConcreteMultiplication(jacobiweight(1,0,d), Jacobi(rs.b-i,rs.a,d)) for i in min(rs.b, Sf.β)-1:-1:1)
Base.Generator{StepRange{Int64, Int64}, var"#15#16"}(var"#15#16"(), -1:-1:0)

julia> Base.@default_eltype(G)
Any

julia> ((rs,Sf,d) -> (G = (ConcreteMultiplication(jacobiweight(1,0,d), Jacobi(rs.b-i,rs.a,d)) for i in min(rs.b, Sf.β)-1:-1:1); Base.@default_eltype(G)))(rs,Sf,d)
ConcreteMultiplication{JacobiWeight{ConstantSpace{ChebyshevInterval{Float64}, Float64}, ChebyshevInterval{Float64}, Float64, Int64}, Jacobi{ChebyshevInterval{Float64}, Float64, Int64}, Float64}

```

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [September 5, 2023, 11:39am UTC](https://discourse.julialang.org/t/why-are-returned-types-different-in-comprehension-over-an-empty-range-if-called-from-a-function-vs-top-level/103533/2 "2023-09-05T11:39:39Z")

</div>

Comprehensions create closures, which capture variables. Creating limited scopes, such as a `let` block or a small function help to avoid making them mutable `Any` boxes that can’t infer.

You can try a `let` block around the comprehension as well to see if it also infers instead of `Any[]`. I expect it to.

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [September 5, 2023, 11:46am UTC](https://discourse.julialang.org/t/why-are-returned-types-different-in-comprehension-over-an-empty-range-if-called-from-a-function-vs-top-level/103533/3 "2023-09-05T11:46:29Z")

</div>

My idea was to copy-paste existing codes to the REPL for quick testing, but looks like that won’t work

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [September 5, 2023, 1:13pm UTC](https://discourse.julialang.org/t/why-are-returned-types-different-in-comprehension-over-an-empty-range-if-called-from-a-function-vs-top-level/103533/4 "2023-09-05T13:13:26Z")

</div>

Yes, that’s unfortunately common when closures are involved.  
Although for me, normally it is that code works in the REPL, but not inside the scope of an `@testset`, as the latter causes some variable defined after the closure to get captured, producing incorrect results (while later definitions of course can’t be captured in the REPL).
