# Is this pure?

**URL:** https://discourse.julialang.org/t/is-this-pure/8050
**Category:** General Usage
**Created:** [December 28, 2017, 10:20pm UTC](https://discourse.julialang.org/t/is-this-pure/8050 "2017-12-28T22:20:51Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)
#### Post date: [December 28, 2017, 10:20pm UTC](https://discourse.julialang.org/t/is-this-pure/8050/1 "2017-12-28T22:20:51Z")

</div>

```julia
Base.@pure which_key(tuple::NTuple{N, Symbol}, key::Symbol) where N =
    map(x -> x == key, tuple)

```

---

<div class="post-metadata">

### Author: ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)
#### Post date: [January 1, 2018, 2:20pm UTC](https://discourse.julialang.org/t/is-this-pure/8050/2 "2018-01-01T14:20:32Z")

</div>

According to the definition in [#414](https://github.com/JuliaLang/julia/issues/414#issuecomment-31042912), further discussed in [#14324](https://github.com/JuliaLang/julia/issues/14324), it seems so:

```julia
julia> which_key(tuple::NTuple{N, Symbol}, key::Symbol) where N =
           map(x -> x == key, tuple)
which_key (generic function with 1 method)

julia> a1 = (:x,:y,:z); a2 = (:x,:y,:z);

julia> k1 = :x; k2 = :x;

julia> a1 === a2
true

julia> k1 === k2
true

julia> which_key(a1, k1) === which_key(a2, k2)
true

```

But I see you commented on that second issue, so I doubt this comment is of any use to you!

---

<div class="post-metadata">

### Author: ![vchuravy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vchuravy/32/8_2.png) [@vchuravy](https://discourse.julialang.org/u/vchuravy)
#### Post date: [January 1, 2018, 3:12pm UTC](https://discourse.julialang.org/t/is-this-pure/8050/3 "2018-01-01T15:12:30Z")

</div>

I would generally discourage using the `@pure` annotations. It’s primary usage is for inference and it is hard to use correctly.

---

<div class="post-metadata">

### Author: ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)
#### Post date: [January 1, 2018, 4:18pm UTC](https://discourse.julialang.org/t/is-this-pure/8050/4 "2018-01-01T16:18:15Z")

</div>

You need the `@pure` annotation here to get constant propagation.

---

<div class="post-metadata">

### Author: ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)
#### Post date: [January 3, 2018, 12:50am UTC](https://discourse.julialang.org/t/is-this-pure/8050/5 "2018-01-03T00:50:32Z")

</div>

It’s true that it is computing a pure result, since we can inline the `map` call to create an equivalent function that makes it more apparent that we’re only using pure functions:

```julia
which_key(tuple::Tuple{}, key::Symbol) = ()
which_key(tuple::Tuple{Vararg{Symbol}}, key::Symbol) =
    (first(tuple) === key, which_key(Base.tail(tuple), key)...)

```

Although, if you try `code_typed` on this, you’ll soon discover that IPO constant-propagation gets disabled by recursion, so I’d guess that probably doesn’t help as much as you might have liked. (and after several minutes of playing with this, I can say that it’s surprisingly hard to bypass that heuristic – which is nice since it means that at least it’s fairly robust to style changes.)

In the end, I decided the most feasible way to bypass it was just to give in and use a generated function after moving everything into the type-domain, so, um, yeah, this:

```julia
which_key4(tuple::NTuple{N, Symbol}, key::Symbol) =
    _which_key4(Val(tuple), Val(key))
_which_key4(::Val{tuple}, ::Val{key}) where {tuple, key} =
    ntuple(i -> tuple[i] === key, Val(length(tuple)))

```

* * *

addendum:  
An even more minimal implementation (e.g. the same as above after more manual inlining):

```julia
which_key(tuple::Tuple{Vararg{Symbol}}, key::Symbol) =
    _which_key(key, tuple...)
_which_key(key::Symbol) = ()
Base.@pure _which_key(key::Symbol, first::Symbol, tail...) =
    (first === key, _which_key(key, tail...)...)

```

---

<div class="post-metadata">

### Author: ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)
#### Post date: [January 3, 2018, 1:09am UTC](https://discourse.julialang.org/t/is-this-pure/8050/6 "2018-01-03T01:09:31Z")

</div>

Ok, great! Since I have an expert here, to get constant propagation to work recursively, I need to define my own tail function:

```julia
Base.@pure argtail(x, rest...) = rest
tail(x) = argtail(x...)

```

Again, a `@pure` annotation is necessary here, even though `argtail` seems very pure.

---

<div class="post-metadata">

### Author: ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)
#### Post date: [January 3, 2018, 1:20am UTC](https://discourse.julialang.org/t/is-this-pure/8050/7 "2018-01-03T01:20:57Z")

</div>

Also, would it be kosher to take off the type restrictions?

```julia
Base.@pure which_key(tuple::Tuple, key) where N =
    map(x -> x == key, tuple)

```

---

<div class="post-metadata">

### Author: ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)
#### Post date: [January 3, 2018, 1:29am UTC](https://discourse.julialang.org/t/is-this-pure/8050/8 "2018-01-03T01:29:36Z")

</div>

No, it’s not pure without the restrictions.

It seems like argtail just needs an update to the inference code
