# Zero-cost way to check if \`NamedTuple\` has a field?

**URL:** <https://discourse.julialang.org/t/zero-cost-way-to-check-if-namedtuple-has-a-field/24684>\
**Category:** General Usage\
**Tags:** question\
**Created:** [May 28, 2019, 9:56am UTC](https://discourse.julialang.org/t/zero-cost-way-to-check-if-namedtuple-has-a-field/24684 "2019-05-28T09:56:52Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [May 28, 2019, 9:56am UTC](https://discourse.julialang.org/t/zero-cost-way-to-check-if-namedtuple-has-a-field/24684/1 "2019-05-28T09:56:52Z")

</div>

Is there a way to check if a `NamedTuple` has a field `:a` that is elided by the compiler? For example, let `t=(a=1, b=2)`. Then the fact that `t` has fields `:a,:b` is known at compile time (because this info is in the type of `t`):

```julia
julia> typeof(t)
NamedTuple{(:a, :b),Tuple{Int64,Int64}}

```

However both `haskey(t, :a)` and `:a in propertynames(t)` don’t seem to be elided by the compiler (I checked by looking at the `@code_native` of these calls).

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [May 28, 2019, 10:15am UTC](https://discourse.julialang.org/t/zero-cost-way-to-check-if-namedtuple-has-a-field/24684/2 "2019-05-28T10:15:00Z")

</div>

> [@e3c6](#):
>
> don’t seem to be elided by the compiler (I checked by looking at the `@code_native` of these calls).

```julia
julia> t = (a = 3, b= 2)
(a = 3, b = 2)

julia> typeof(t)
NamedTuple{(:a, :b),Tuple{Int64,Int64}}

julia> f(t) = haskey(t, :a)
f (generic function with 1 method)

julia> @code_llvm f(t)

; @ REPL[30]:1 within `f`
define i8 @julia_f_12916({ i64, i64 } addrspace(11)* nocapture nonnull readonly dereferenceable(16)) {
top:
  ret i8 1
}

julia> g(t) = haskey(t, :q)
g (generic function with 1 method)

julia> @code_llvm g(t)

; @ REPL[34]:1 within `g`
define i8 @julia_g_12931({ i64, i64 } addrspace(11)* nocapture nonnull readonly dereferenceable(16)) {
top:
  ret i8 0
}

```

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [May 28, 2019, 10:23am UTC](https://discourse.julialang.org/t/zero-cost-way-to-check-if-namedtuple-has-a-field/24684/3 "2019-05-28T10:23:03Z")

</div>

Maybe related: [Is the first key of a NamedTuple special?](https://discourse.julialang.org/t/is-the-first-key-of-a-namedtuple-special/21256)

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [May 28, 2019, 10:25am UTC](https://discourse.julialang.org/t/zero-cost-way-to-check-if-namedtuple-has-a-field/24684/4 "2019-05-28T10:25:00Z")

</div>

Not really relevant here since:

```julia
julia> b(t) = haskey(t, :b)
b (generic function with 1 method)

julia> @code_llvm b(t)

; @ REPL[42]:1 within `b'
define i8 @julia_b_12946({ i64, i64 } addrspace(11)* nocapture nonnull readonly dereferenceable(16)) {
top:
  ret i8 1
}

```

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [May 28, 2019, 10:27am UTC](https://discourse.julialang.org/t/zero-cost-way-to-check-if-namedtuple-has-a-field/24684/5 "2019-05-28T10:27:56Z")

</div>

I thought it might still be relevant as the OP also mentions `in` instead of `haskey`. And there we have

```julia
julia> @code_llvm :b in propertynames((a=2, b=3))

; @ operators.jl:948 within `in'
; Function Attrs: uwtable
define i8 @julia_in_10617(%jl_value_t addrspace(10)* nonnull, %jl_value_t addrspace(10)* nonnull align 8 dereferenceable(16)) #0 {
top:
; @ operators.jl:949 within `in'
; ┌ @ tuple.jl:43 within `iterate' @ tuple.jl:43
; │┌ @ tuple.jl:24 within `getindex'
    %2 = addrspacecast %jl_value_t addrspace(10)* %1 to %jl_value_t addrspace(11)*
    %3 = bitcast %jl_value_t addrspace(11)* %2 to %jl_value_t addrspace(10)* addrspace(11)*
    %value_phi7 = load %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)* addrspace(11)* %3, align 8
; └└
; @ operators.jl:950 within `in'
; ┌ @ operators.jl:83 within `=='
   %4 = addrspacecast %jl_value_t addrspace(10)* %value_phi7 to %jl_value_t addrspace(11)*
   %5 = addrspacecast %jl_value_t addrspace(10)* %0 to %jl_value_t addrspace(11)*
   %6 = icmp eq %jl_value_t addrspace(11)* %4, %5
; └
; @ operators.jl:953 within `in'
  br i1 %6, label %L7, label %L8.lr.ph

L8.lr.ph: ; preds = %top
  %7 = bitcast %jl_value_t addrspace(10)* %1 to %jl_value_t addrspace(10)* addrspace(10)*
  %8 = addrspacecast %jl_value_t addrspace(10)* addrspace(10)* %7 to %jl_value_t addrspace(10)* addrspace(11)*
  br label %L8

L7: ; preds = %L24, %L8, %top
  %merge = phi i8 [1, %top], [0, %L8], [1, %L24]
; @ operators.jl:954 within `in'
  ret i8 %merge

L8: ; preds = %L8.lr.ph, %L24
  %value_phi18 = phi i64 [2, %L8.lr.ph], [%11, %L24]
; ┌ @ tuple.jl:43 within `iterate'
   %value_phi1.off = add nsw i64 %value_phi18, -1
   %9 = icmp ugt i64 %value_phi1.off, 1
   br i1 %9, label %L7, label %L24

L24: ; preds = %L8
; │┌ @ tuple.jl:24 within `getindex'
    %10 = getelementptr inbounds %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)* addrspace(11)* %8, i64 %value_phi1.off
; │└
; │┌ @ int.jl:53 within `+'
    %11 = add nuw nsw i64 %value_phi18, 1
; └└
; @ operators.jl:949 within `in'
; ┌ @ tuple.jl:43 within `iterate' @ tuple.jl:43
; │┌ @ tuple.jl:24 within `getindex'
    %value_phi = load %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)* addrspace(11)* %10, align 8
; └└
; @ operators.jl:950 within `in'
; ┌ @ operators.jl:83 within `=='
   %12 = addrspacecast %jl_value_t addrspace(10)* %value_phi to %jl_value_t addrspace(11)*
   %13 = icmp eq %jl_value_t addrspace(11)* %12, %5
; └
; @ operators.jl:953 within `in'
  br i1 %13, label %L7, label %L8
}

```

---

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [May 28, 2019, 12:21pm UTC](https://discourse.julialang.org/t/zero-cost-way-to-check-if-namedtuple-has-a-field/24684/6 "2019-05-28T12:21:57Z")

</div>

Okay. So for now I’ll use `haskey` instead of `in`.  
This seems like a compiler bug? Should someone raise an issue?

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [May 28, 2019, 12:25pm UTC](https://discourse.julialang.org/t/zero-cost-way-to-check-if-namedtuple-has-a-field/24684/7 "2019-05-28T12:25:10Z")

</div>

> [@e3c6](#):
>
> This seems like a compiler bug? Should someone raise an issue?

It is not a bug. But there is an issue open about it [Constant propagation for tuple in operator only works for first element · Issue #28844 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/28844).

Also, the problem is not only with `in` but with `propertynames`.
