# How can you dispatch on Iterator eltype including generators?

**URL:** <https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511>\
**Category:** General Usage\
**Created:** [February 6, 2019, 5:46pm UTC](https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511 "2019-02-06T17:46:53Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![ndinsmore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ndinsmore/32/7433_2.png) [@ndinsmore](https://discourse.julialang.org/u/ndinsmore)\
**Post date:** [February 6, 2019, 5:46pm UTC](https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511/1 "2019-02-06T17:46:53Z")

</div>

Ho can you dispatch on Iterator eltype including generators? I ask in an attempt to fix the following interface problem.

Right now I am working on the get function of an interface that has many different types to dispatch, and potentially a lot of over head for each get initially. Something like:

```julia
struct InterfaceIndirect index::Int64 end
struct ApplicationIndirect ref::InterfaceIndirect end

function interface_get(indirect::InterfaceIndirect)
    #lots of prework which makes it impractical to broadcast to this function
    prework=rand(100_000_000) 
    return prework[indirect.index]
end

function interface_get(indirect::AnotherInterfaceIndirect)
    #same kind of thing as above but different
end

function interface_get(v_indirect::Vector{InterfaceIndirect})
    #lots of prework
    prework=rand(100_000_000)
    return [prework[indirect.index] for indirect in v_ind ]
end

function interface_get(v_indirect::Vector{AnotherInterfaceIndirect})
    #ditto
end

function application_get(app_indirect::ApplicationIndirect)
    interface_get(app_indirect.ref)
end

function application_get(v_app_indirect::Vector{ApplicationIndirect})
    ###This temporary array sucks####
    v_indirect = [app_indirect.ref for app_indirect in v_app_indirect]
    interface_get(v_indirect)
end

```

The temporary array for the application vector indirection seems sub-optimal

Now with that iteration and generators are so fast it would be great if I could instead to something like:

```julia
 interface_get(iter::IT) where IT = _interface_get(eltype(IT),iter)

function _interface_get(::Type{T}, iter) where T <: InterfaceIndirect
    #lots of prework
    prework=rand(100_000_000)
    return [prework[indirect.index] for indirect in iter ]
end

function application_get(v_app_indirect::Vector{ApplicationIndirect})
    #No more temporary array
    interface_get(app_indirect.ref for app_indirect in v_app_indirect)
end

```

But unfortunately Generators do not have an eltype, so that implementation can not be used.  
As I recently inquired about it:

> [@Should Generators finally be given eltype](https://discourse.julialang.org/t/should-generators-finally-be-given-eltype/20507):
>
> With the compiler improvements that went into v1 is it finally time to allow Generators to return an element type? With union splitting, it now appears that all the needed information can be inferred at compile-time. So shouldn’t something as simple as: function Base.IteratorEltype(::Type{Generator{I,T}}) where {I,T} Base.IteratorEltype(I)===Base.HasEltype() && Length(ITA=Base.return\_types(T,Tuple(I))) == 1 && ITA[1] != Union{} && return…

So I ask what is the implementation pattern that gets around this? Or is there an alternative way to achieve this.

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [February 6, 2019, 9:33pm UTC](https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511/2 "2019-02-06T21:33:48Z")

</div>

Good question! First, I noticed that the prework calculation and indexing is duplicated in the scalar and vector methods in your example. If this logic is indeed repeated in your actual code, a good first step would be to remove the duplication by creating the following methods:

```julia
function prework()
    # prework goes here
    rand(100_000)
end

function lookup(pre, idx)
    # get logic goes here (assuming it's more than just an index lookup)
    pre[idx]
end

```

Now onto the dispatch question. I would recommend creating generic `map` versions of the scalar and vector getters, that accept a function that generates the lookup index (or whatever is needed to access the prework):

```julia
function map_get(idx_getter::Function, e)
    pre = prework()
    lookup(pre, idx_getter(e))
end

function map_get(idx_getter::Function, v::AbstractVector)
    pre = prework()
    [lookup(pre, idx_getter(e)) for e in v]
end

```

With this created, it’s simply a matter of implementing an index getter and forward to `map_get` in order to create the get functionality for each type:

```julia
interface_get(indirect) = map_get(e -> e.index, indirect)

application_get(app_indirect) = map_get(e -> e.ref.index, app_indirect)

```

Note in particular that you no longer need to create separate methods for scalars and vectors, it’s handled by `map_get`. And if you add other containers, you’ll only need to add a single `map` version for that container.

(Note: I don’t know what your actual code looks like, but if the prework is not always the same, perhaps you don’t want to generate it in the `map` functions, but in the callers, and pass it to `map_get`. Or pass it as a function, like `idx_getter`.)

All of this should be type stable and fairly performant:

```julia
julia> code_warntype(interface_get, (InterfaceIndirect,))
Body::Float64

julia> code_warntype(interface_get, (Vector{InterfaceIndirect},))
Body::Array{Float64,1}

julia> code_warntype(application_get, (ApplicationIndirect,))
Body::Float64

julia> code_warntype(application_get, (Vector{ApplicationIndirect},))
Body::Array{Float64,1}

```

> **Click here for full code, plus a test.**
>
> ```julia
> using BenchmarkTools
> 
> struct InterfaceIndirect index::Int64 end
> struct ApplicationIndirect ref::InterfaceIndirect end
> 
> function prework()
> # prework goes here
> rand(100_000)
> end
> 
> function lookup(pre, idx)
> # get logic goes here (assuming it's more than just an index lookup)
> pre[idx]
> end
> 
> function map_get(idx_getter::Function, e)
> pre = prework()
> lookup(pre, idx_getter(e))
> end
> 
> function map_get(idx_getter::Function, v::AbstractVector)
> pre = prework()
> [lookup(pre, idx_getter(e)) for e in v]
> end
> 
> interface_get(indirect) = map_get(e -> e.index, indirect)
> 
> application_get(app_indirect) = map_get(e -> e.ref.index, app_indirect)
> 
> function timeit()
> v = 1:10000 .|> n -> InterfaceIndirect(n)
> @btime interface_get($v[1])
> @btime interface_get($v)
> v = 1:10000 .|> n -> ApplicationIndirect(InterfaceIndirect(n))
> @btime application_get($v[1])
> @btime application_get($v)
> nothing
> end
> 
> timeit()
> 
> ```

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [February 6, 2019, 10:02pm UTC](https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511/3 "2019-02-06T22:02:59Z")

</div>

(How does one get the “unfold for full code” to work?)

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [February 6, 2019, 10:12pm UTC](https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511/4 "2019-02-06T22:12:24Z")

</div>

Just click on that line! Edited to clarify.

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [February 6, 2019, 10:16pm UTC](https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511/5 "2019-02-06T22:16:50Z")

</div>

I mean what did you do so that happens to appear in discourse and displays as it does?

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [February 6, 2019, 10:19pm UTC](https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511/6 "2019-02-06T22:19:26Z")

</div>

When you compose a post, there’s a little cogwheel in the menu. Click on that, then click “Hide Details”.

---

<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:** [February 7, 2019, 8:15am UTC](https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511/7 "2019-02-07T08:15:23Z")

</div>

If you need to precompute something once, but hide that from the interface, you may find

> [@Best practice approach for caching data in objects](https://discourse.julialang.org/t/best-practice-approach-for-caching-data-in-objects/20419):
>
> Something that’s come up repeatedly for me this last week in different contexts (and also many times before) is how do you approach the case where you sometimes want to be able to store intermediary results? For a clearly contrived MWE, let’s say we have a type wrapping an Array and in certain contexts we often evaluate the extrema. Let’s say we don’t have to worry about cache invalidation (e.g. either 1) the values of the array don’t change or 2) we can only change the value using a setter fun…

useful.

---

<div class="post-metadata">

**Author:** ![ndinsmore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ndinsmore/32/7433_2.png) [@ndinsmore](https://discourse.julialang.org/u/ndinsmore)\
**Post date:** [February 7, 2019, 5:48pm UTC](https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511/8 "2019-02-07T17:48:20Z")

</div>

The one aspect to the approach, due to a requirement I may not have articulated is the the `interface_get(...)` method need to be-able to dispatch on multiple types in its own module and the prework that is done is dependent on the type.

So in the example that won’t work because of the lack of eltype on Generators you would see::

```julia
 interface_get(iter::IT) where IT = _interface_get(eltype(IT),iter)

function _interface_get(::Type{InterfaceIndirect}, iter) 
    prework=preworker(::Type{InterfaceIndirect})
    return [prework[indirect.index] for indirect in iter ]
end

function _interface_get(::Type{AnotherInterfaceIndirect}, iter) 
    prework=preworker(::Type{AnotherInterfaceIndirect})
    return [prework[indirect.index] for indirect in iter ]
end

```

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [February 7, 2019, 8:57pm UTC](https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511/9 "2019-02-07T20:57:03Z")

</div>

Why can’t you just take the element / eltype of the first element and dispatch on that?

```julia
function interface_get(iter)
    prework = preworker(first(iter))
    return [prework[indirect.index] for indirect in iter]
end

```

If this is not sufficient, perhaps you could post a more complete MWE that compiles and illustrates your problem?

---

<div class="post-metadata">

**Author:** ![ndinsmore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ndinsmore/32/7433_2.png) [@ndinsmore](https://discourse.julialang.org/u/ndinsmore)\
**Post date:** [February 8, 2019, 1:35pm UTC](https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511/10 "2019-02-08T13:35:42Z")

</div>

> [@bennedich](#):
>
> Why can’t you just take the element / eltype of the first element and dispatch on that?

Yes, that would work it just feels un-satisfying though.

Is the problem that I am trying to do this in an un-Julian way? Would broadcasting be a better approach?  
Lets say I have:

```julia
index(ojb::ApplicationIndirect) = obj.ref

```

How could I get this to work:

```julia
function application_get(v_app_indirect::Vector{ApplicationIndirect})
    interface_get.(index.(v_app_indirect))
end

```

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [February 8, 2019, 2:25pm UTC](https://discourse.julialang.org/t/how-can-you-dispatch-on-iterator-eltype-including-generators/20511/11 "2019-02-08T14:25:09Z")

</div>

I don’t see how broadcasting would be better. Your example will end up calling `interface_get` with single elements, so you will be calculating `prework` over and over again. One way to solve that is using caching / lazy initialization like in Tamas’ link above (see [the Lazy struct I proposed](https://discourse.julialang.org/t/best-practice-approach-for-caching-data-in-objects/20419/5)). Then you could push the calculation of prework all the way to the lookup method (where the prework is accessed). Whether that’s better or not is hard to tell – in my experience lazy variables can make the code slightly more complex and increase the risk of errors, and the lazy indirection will also add a small overhead to the lookup (few nanoseconds if cached; probably acceptable unless the lookup is trivial like in the example above).
