# Constant propagation with Val and non-struct types

**URL:** <https://discourse.julialang.org/t/constant-propagation-with-val-and-non-struct-types/25100>\
**Category:** Internals & Design\
**Tags:** question\
**Created:** [June 9, 2019, 7:30pm UTC](https://discourse.julialang.org/t/constant-propagation-with-val-and-non-struct-types/25100 "2019-06-09T19:30:10Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![bug-brain](https://avatars.discourse-cdn.com/v4/letter/b/ea666f/32.png) [@bug-brain](https://discourse.julialang.org/u/bug-brain)\
**Post date:** [June 9, 2019, 7:30pm UTC](https://discourse.julialang.org/t/constant-propagation-with-val-and-non-struct-types/25100/1 "2019-06-09T19:30:10Z")

</div>

The type `Val` can be used to handily associate values with constants by writing a method of a function for each pair. It’s even handier to define a function that wraps the values in `Val` so you don’t have to type it.

For some reason the wrapper stops constant propagation when the values are of type `Integer` or `Symbol`. When `t` in the snippet below is changed to `nothing` the propagation works and the functions bodies are just `return true`.

It works when adding `@pure` but since the compiler doesn’t recognize it on its own and the case seems to be quite simple I’m wondering if I missed something and it could be unsafe to do so. Julia version is 1.1.0.

```julia
using InteractiveUtils

const t = :symbol
const T = typeof(t)

selector1(::Val{t}) = true
wrapper1(x::T) = selector1(Val(x))
test1() = wrapper1(t)
@code_warntype test1()

selector2(::Type{Val{t}}) = true
wrapper2(x::T) = selector2(Val{x})
test2() = wrapper2(t)
@code_warntype test2()

```

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [June 10, 2019, 2:11pm UTC](https://discourse.julialang.org/t/constant-propagation-with-val-and-non-struct-types/25100/3 "2019-06-10T14:11:29Z")

</div>

Not sure. I thought that for `Symbol` this could be because `isimmutable(:symbol) == false` and `Symbol.mutable == true`. Even though `Symbol`s are functionally immutable, the type system currently doesn’t treat them as such for certain technical reasons (see [https://github.com/JuliaLang/julia/issues/30210](https://github.com/JuliaLang/julia/issues/30210)). This probably breaks constant prop. But then I would have expected the `const t = 1` variant to work, so there’s probably something else in play here.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [June 10, 2019, 3:40pm UTC](https://discourse.julialang.org/t/constant-propagation-with-val-and-non-struct-types/25100/4 "2019-06-10T15:40:07Z")

</div>

Interestingly, if you define the other case the compiler is then happy to do this at compile-time. Note that `@code_warntype` doesn’t do inlining by default so it doesn’t display all the optimizations.

```julia
julia> @code_typed test1()
CodeInfo(
1 ─ %1 = invoke Main.wrapper1(Main.t::Symbol)::Core.Compiler.Const(true, false)
└── return %1
) => Bool

julia> selector1(x) = false
selector1 (generic function with 2 methods)

julia> @code_typed test1()
CodeInfo(
1 ─ return true
) => Bool

```

Of course, I’d recommend just using constant propagation and branches instead of `Val` dispatch:

```julia
const t = :symbol
selector3(x) = x == t
wrapper3(x) = selector3(x)
test3() = wrapper3(t)

julia> @code_typed test3()
CodeInfo(
1 ─ return true
) => Bool

```

---

<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:** [June 10, 2019, 4:51pm UTC](https://discourse.julialang.org/t/constant-propagation-with-val-and-non-struct-types/25100/5 "2019-06-10T16:51:24Z")

</div>

> [@tkoolen](#):
>
> Not sure. I thought that for `Symbol` this could be because `isimmutable(:symbol) == false` and `Symbol.mutable == true` . Even though `Symbol` s are functionally immutable, the type system currently doesn’t treat them as such for certain technical reasons (see [https://github.com/JuliaLang/julia/issues/30210](https://github.com/JuliaLang/julia/issues/30210)). This probably breaks constant prop. But then I would have expected the `const t = 1` variant to work, so there’s probably something else in play here.

Symbols definitely participate in constant propagation, otherwise `getproperty` would not work well.

---

<div class="post-metadata">

**Author:** ![bug-brain](https://avatars.discourse-cdn.com/v4/letter/b/ea666f/32.png) [@bug-brain](https://discourse.julialang.org/u/bug-brain)\
**Post date:** [June 11, 2019, 8:38pm UTC](https://discourse.julialang.org/t/constant-propagation-with-val-and-non-struct-types/25100/6 "2019-06-11T20:38:15Z")

</div>

> [@mbauman](#):
>
> Interestingly, if you define the other case the compiler is then happy to do this at compile-time.

That helped! Apparently the compiler knows that the method will return a constant result but still leaves the call in if there is no fallback method present (unless `T` is a fieldles struct / empty tuple).

> [@mbauman](#):
>
> Of course, I’d recommend just using constant propagation and branches instead of `Val` dispatch:

Sadly this approach is not possible in my real code because the methods are added dynamically so that the function acts as Dict with inferable value type.

---

<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:** [June 12, 2019, 6:18am UTC](https://discourse.julialang.org/t/constant-propagation-with-val-and-non-struct-types/25100/7 "2019-06-12T06:18:05Z")

</div>

Constant propagation is disabled by recursion, so for anything that’s not trivial, passing things around in types is probably the way to go.
