# Collect and type inference

**URL:** https://discourse.julialang.org/t/collect-and-type-inference/53152
**Category:** Internals & Design
**Tags:** question
**Created:** [January 11, 2021, 10:02am UTC](https://discourse.julialang.org/t/collect-and-type-inference/53152 "2021-01-11T10:02:14Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [January 11, 2021, 10:02am UTC](https://discourse.julialang.org/t/collect-and-type-inference/53152/1 "2021-01-11T10:02:14Z")

</div>

While the type-widening of `collect` for `EltypeUnknown` is extremely useful for generic code, my recent experience with a large codebase with time-consuming and occasionally failing inference suggests that these two alternatives would be useful:

1. a version of `collect` which assumes that all values from an iterator have the same type (practically, it would get one element, and use its type from then on), and it is free to error and abort otherwise,

2. a version of `collect` which, when two values do not have the same _concrete_ type, can just widen to `Any` and be done with it.

Parts of the machinery for this already exist in or could be adapted from `base/array.jl`, but are not part of the exposed API. I thought I would ask before opening an issue. Suggestions for the API are also welcome.

---

<div class="post-metadata">

### Author: ![antoine-levitt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/antoine-levitt/32/4008_2.png) [@antoine-levitt](https://discourse.julialang.org/u/antoine-levitt)
#### Post date: [January 11, 2021, 10:18am UTC](https://discourse.julialang.org/t/collect-and-type-inference/53152/2 "2021-01-11T10:18:04Z")

</div>

One issue is that calls to `collect` can happen implicitly, eg in array comprehensions. Maybe a macro that changes the behavior of the following expressions, like with `@views` and `@.`?

---

<div class="post-metadata">

### Author: ![nalimilan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nalimilan/32/147_2.png) [@nalimilan](https://discourse.julialang.org/u/nalimilan)
#### Post date: [January 11, 2021, 10:24am UTC](https://discourse.julialang.org/t/collect-and-type-inference/53152/3 "2021-01-11T10:24:47Z")

</div>

> [@Tamas\_Papp](#):
>
> 1. a version of `collect` which assumes that all values from an iterator have the same type (practically, it would get one element, and use its type from then on), and it is free to error and abort otherwise,

Are you sure that would help inference? If inference fails in the first place, it doesn’t even know the type of the first element… Likewise, I doubt that inference can be made faster by asserting that the result type will be concrete (if you don’t know it already).

Could you develop what are the problems you encountered? In [this PR](https://github.com/JuliaLang/julia/pull/30485) I’ve made steps towards making `broadcast` inferable even when the result has a `Union` eltype. It used to work in previous versions of Julia, but now it’s been broken by changed in inference. But there’s probably a way to finish this and extend it to `map`.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [January 11, 2021, 11:31am UTC](https://discourse.julialang.org/t/collect-and-type-inference/53152/4 "2021-01-11T11:31:13Z")

</div>

> [@nalimilan](#):
>
> Are you sure that would help inference? If inference fails in the first place, it doesn’t even know the type of the first element…

I would want to help the compiler by giving up early instead of figuring out the exact `Union` etc when it is not likely to help me much. This is not the right semantics for `Union{T,Missing}` and similar, but it has its applications.

> [@nalimilan](#):
>
> Could you develop what are the problems you encountered?

I am encountering some inference problems on 1.6 in a large codebase with deeply nested types. What happens with a result type `Foo{T}` is that `[f(x) for x in X]` figures out a result type `Union{Vector{Foo},Vector{Foo{S}}}` or similar for a concrete `S`, even if the type of `X` and `f` are inferred fine.

I could not make a sensible MWE yet.

---

<div class="post-metadata">

### Author: ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)
#### Post date: [January 11, 2021, 11:40am UTC](https://discourse.julialang.org/t/collect-and-type-inference/53152/5 "2021-01-11T11:40:35Z")

</div>

> [@Tamas\_Papp](#):
>
> a version of `collect` which, when two values do not have the same _concrete_ type, can just widen to `Any` and be done with it.

Would something like this work in your case?

```julia
julia> function _eltype(iter)
           T = eltype(iter)
           return Base.isconcretetype(T) ? T : Any
       end
_eltype (generic function with 1 method)

julia> _collect(iter) = collect(_eltype(iter), iter)
_collect (generic function with 1 method)

julia> _collect(rand([1, missing]) for _ in 1:10)
10-element Vector{Any}:
 1
 1
 1
 1
 1
  missing
 1
  missing
  missing
 1

```

Edit: Sorry, you still need to define this to make it work with concretely typed generators:

```julia
function _eltype(gen::Base.Generator)
    T = Base.promote_op(gen.f, eltype(gen.iter))
    return Base.isconcretetype(T) ? T : Any
end

```

---

<div class="post-metadata">

### Author: ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)
#### Post date: [January 13, 2021, 12:00pm UTC](https://discourse.julialang.org/t/collect-and-type-inference/53152/6 "2021-01-13T12:00:20Z")

</div>

Not quite what you want, but maybe a workaround:

1. `collect(typeof(first(itr)), itr)`
2. `collect(Any, itr)`
