# What computations are fine to do within \`Val\`?

**URL:** <https://discourse.julialang.org/t/what-computations-are-fine-to-do-within-val/35216>\
**Category:** General Usage\
**Tags:** type\
**Created:** [February 27, 2020, 8:55am UTC](https://discourse.julialang.org/t/what-computations-are-fine-to-do-within-val/35216 "2020-02-27T08:55:52Z")\
**Posts on this page:** 8\
**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:** [February 27, 2020, 8:55am UTC](https://discourse.julialang.org/t/what-computations-are-fine-to-do-within-val/35216/1 "2020-02-27T08:55:53Z")

</div>

Here are two (highly artificial) examples:

```julia
f(::Array{T,N}, ::Array{T,M}) where {T,N,M} = zeros(T, ntuple(i -> 2, Val(N+M)))
g(::Array{T,N}, ::Array{T,M}) where {T,N,M} = zeros(T, ntuple(i -> 2, Val(round(Int, √abs(N+M)))))

```

The first is type stable but the second is not (you can check with `@code_warntype`). Why?

---

<div class="post-metadata">

**Author:** ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)\
**Post date:** [February 27, 2020, 9:40am UTC](https://discourse.julialang.org/t/what-computations-are-fine-to-do-within-val/35216/2 "2020-02-27T09:40:05Z")

</div>

Or even simpler:

```julia
f(::Val{N}) where {N} = Val(N^3)
g(::Val{N}) where {N} = Val(N^4)

```

The first infers, the second doesn’t.

Could it have to do with internal compiler inference heuristics on when to bail? `N^4` might just cross a complexity boundary that `N^3` doesn’t.

---

<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:** [February 27, 2020, 9:56am UTC](https://discourse.julialang.org/t/what-computations-are-fine-to-do-within-val/35216/3 "2020-02-27T09:56:00Z")

</div>

Is there an easy way to understand when it works and when it doesn’t?

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [February 27, 2020, 11:04am UTC](https://discourse.julialang.org/t/what-computations-are-fine-to-do-within-val/35216/4 "2020-02-27T11:04:46Z")

</div>

I think this has to do with how `Base.literal_pow(^, x, Val(3))` has a specialized implementation, which just expands to `x*x*x`, whereas for `Val(4)`, it falls back to `Base.^`, which uses a power by squaring algorithm, that is probably too complex for the compiler to propagate constants through.

---

<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 27, 2020, 12:09pm UTC](https://discourse.julialang.org/t/what-computations-are-fine-to-do-within-val/35216/5 "2020-02-27T12:09:06Z")

</div>

You can simplify the original problem a bit to just an arbitrary parametric type like below. Removing `sqrt` fixes inference, and so does making the calculation pure (not that I would recommend this):

```julia
struct Foo{T} end

Base.@pure calc(x::Int, y::Int) = round(Int, sqrt(abs(x + y)))

g(::Foo{N}, ::Foo{M}) where {N,M} = Foo{calc(N,M)}()
g2(::Foo{N}, ::Foo{M}) where {N,M} = Foo{abs(N+M)}()

F = Foo{2}()
@code_warntype g(F, F) # OK
@code_warntype g2(F, F) # OK

```

Unfortunately, I don’t know a systematic way to diagnose these things, just trial and error.

---

<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:** [February 27, 2020, 12:48pm UTC](https://discourse.julialang.org/t/what-computations-are-fine-to-do-within-val/35216/6 "2020-02-27T12:48:07Z")

</div>

I think this is exactly the situation that the `@pure` annotation is meant to solve. Basically it promises that there will never be any methods added to `calc`, `+`, `abs`, `round` or `sqrt` (or any functions that they might call) or any other global state that affect this calculation.

In this particular case, I think that should be safe to assume.

---

<div class="post-metadata">

**Author:** ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)\
**Post date:** [February 27, 2020, 1:30pm UTC](https://discourse.julialang.org/t/what-computations-are-fine-to-do-within-val/35216/7 "2020-02-27T13:30:22Z")

</div>

This is a _very_ useful post for me. It takes a bit of the voodoo out of `Base.@pure`. I understand the problem would arise, however, if the user were to extend `sqrt` with some custom type. What would happen in that case? Would things still work as long as N + M are not of that custom type, or would things break in another way?

---

<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:** [February 27, 2020, 2:05pm UTC](https://discourse.julialang.org/t/what-computations-are-fine-to-do-within-val/35216/8 "2020-02-27T14:05:31Z")

</div>

In this case, `calc` is only defined for `Int`, so `sqrt` will always be called with an `Int`. Adding methods to `sqrt` should be fine. Those methods could not possibly affect the result of `calc` as long as the user is not engaging in serious type piracy.

Of course, extending `calc` to accept user-defined types would be a bad idea. (Also, I think `@pure` functions should not be extended at all after they first have been called.)

Edit: Note that this is my own interpretation of the documentation. I am by no means an expert here.
