# RFC: Reference Iterator for better in place loop modifications

**URL:** https://discourse.julialang.org/t/rfc-reference-iterator-for-better-in-place-loop-modifications/22312
**Category:** Internals & Design
**Created:** [March 25, 2019, 5:19pm UTC](https://discourse.julialang.org/t/rfc-reference-iterator-for-better-in-place-loop-modifications/22312 "2019-03-25T17:19:34Z")
**Posts on this page:** 5
**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: [March 25, 2019, 5:19pm UTC](https://discourse.julialang.org/t/rfc-reference-iterator-for-better-in-place-loop-modifications/22312/1 "2019-03-25T17:19:34Z")

</div>

Has there ever been any discussion of creating a `RefsIterator` type and the accompanying `refs(collection)` which returns a `Ref` to the values of a collection?

So you could write:

```julia
col=collect(1:1000)
for r in refs(col)
    r[]=... r[]...
    ....
end

```

You could of course do `refs(values(dict))` as well but you would want to limit this collections where modification to the values is valid. So no `refs(keys(::Dict))` but maybe `refs(keys(::OrderedDict))` ?

This seems like the easiest way to enable more generic in place modification via loops.

---

<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: [March 25, 2019, 5:26pm UTC](https://discourse.julialang.org/t/rfc-reference-iterator-for-better-in-place-loop-modifications/22312/2 "2019-03-25T17:26:39Z")

</div>

Seems like a nice idea. If somebody wrote a package for this, I’d probably use it.

---

<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: [March 25, 2019, 5:30pm UTC](https://discourse.julialang.org/t/rfc-reference-iterator-for-better-in-place-loop-modifications/22312/3 "2019-03-25T17:30:28Z")

</div>

I would advocate for it to be part of `Base` so that it becomes consistent across the ecosystem.

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [March 25, 2019, 5:38pm UTC](https://discourse.julialang.org/t/rfc-reference-iterator-for-better-in-place-loop-modifications/22312/4 "2019-03-25T17:38:55Z")

</div>

> <https://github.com/JuliaLang/julia/issues/12157>
>
> \#### problem statement:
> 
> a common idiom when working with Associative objects is… to do a set of has / insert / lookup operations:
> 
> \`\`\` julia
> d = Dict()
> if !(key in keys(d))
> d\[key\] = initial\_value
> end
> value = d\[key\]
> \`\`\`
> 
> this syntax has the advantage of only using basic operations, for clarity, but it's also 3x slower than necessary since the dict lookup gets repeated three times. that concern has lead to the introduction of a \`get!\` method that accepts either an object or function, to insert a value if the lookup fails, so that the above code can be rewritten as:
> 
> \`\`\` julia
> d = Dict()
> value = get!(d, key, initial\_value)
> \`\`\`
> 
> or
> 
> \`\`\` julia
> d = Dict()
> value = get!(d, key, () -\> initial\_value)
> \`\`\`
> 
> however, this implementation is still not necessarily faster, since it involves precomputing initial\_value (fine it it's just a constant, but bad if it expensive to compute or creates unnecessary garbage) or invoking a lambda.
> 
> the code to support this one code pattern isn't exactly short, requires a fair amount of code duplication, and even a macro definition is provided (https://github.com/JuliaLang/julia/blob/master/base/dict.jl#L632-L690)
> \#### proposal
> 
> define the \`Ref\` operation on a Dict to return an intelligent indexer object. the above code pattern could then be written as:
> 
> \`\`\` julia
> d = Dict()
> bp = Ref(d, key)
> if isempty(bp)
> bp\[\] = initial\_value
> end
> value = bp\[\]
> \`\`\`
> \#### implementation sketch
> 
> \`\`\` julia
> type RefDict{K, V, D \<: Dict} \<: Ref{V}
> d::D
> k::K
> last\_htindex::Int
> last\_state::Int
> end
> function RefDict{K,V}(d::Dict{K,V}, k)
> key = convert(K, k)
> isequal(key, k) || throw(ArgumentError("k is not a usable key"))
> return RefDict{K,V,typeof(d)}(d, k, 0, 0)
> end
> function isempty(r::RefDict)
> if (d.last\_state != d.changecounter)
> r.last\_htindex = ht\_keyindex2(d, key)
> r.last\_state = d.changecounter
> end
> return r.last\_htindex \> 0
> end
> \`\`\`
> 
> ref https://github.com/JuliaLang/julia/pull/12035#issuecomment-120614758

---

<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: [March 25, 2019, 7:40pm UTC](https://discourse.julialang.org/t/rfc-reference-iterator-for-better-in-place-loop-modifications/22312/5 "2019-03-25T19:40:36Z")

</div>

The time frame in #12157 is a little beyond my julia horizon, so some of the implementation seems a bit heavy.

But I was thinking something as simple as

```nohighlight
struct RefsIterator{T}
    dict::T
end

```

then for dict it would like like

```julia
@propagate_inbounds function Base.iterate(v::T, i::Union{Int,Nothing}=v.dict.idxfloor) where T <:RefsIterator{ValueIterator{<:Dict}}
    i === nothing && return nothing # This is to catch nothing returned when i = typemax
    i = skip_deleted(v.dict, i)
    i === nothing && return nothing # This is to catch nothing returned by skip_deleted
    vals = T <: KeySet ? v.dict.keys : v.dict.vals
    (@inbounds Ref(vals,i), i == typemax(Int) ? nothing : i+1)
end

```

There likely could be some improvement made so that a new ref isn’t created every iteration but it should be that simple.
