# Detect if constant

**URL:** https://discourse.julialang.org/t/detect-if-constant/100246
**Category:** General Usage
**Tags:** constant-propagation
**Created:** [June 12, 2023, 7:56pm UTC](https://discourse.julialang.org/t/detect-if-constant/100246 "2023-06-12T19:56:52Z")
**Posts on this page:** 10
**Page:** 3

<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: [June 16, 2023, 9:18am UTC](https://discourse.julialang.org/t/detect-if-constant/100246/41 "2023-06-16T09:18:46Z")

</div>

Yes, it is fine to use different data structures and call different methods, as long as the branches behave identically from the point of view of an outside observer. So if those methods have visible side-effects, it should be the same side-effects. And the final return value should be the same.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [June 16, 2023, 9:38am UTC](https://discourse.julialang.org/t/detect-if-constant/100246/42 "2023-06-16T09:38:18Z")

</div>

So what you’d require is that the effects in both branches would be the same, right? So not even a difference in task-local state, or other effects?

I mean, that sounds like a very hard requirement that’s extremely difficult to check in practice.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [June 16, 2023, 9:38am UTC](https://discourse.julialang.org/t/detect-if-constant/100246/43 "2023-06-16T09:38:19Z")

</div>

> [@Per](#):
>
> And the final return value should be the same.

So no `rand`s then, that was in OP’s code example earlier. And we’d have to convert the different array types to the same one before a return. This actually seems stricter than the identical behavior suggestion for optionally generated functions.

---

<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: [June 16, 2023, 9:55am UTC](https://discourse.julialang.org/t/detect-if-constant/100246/44 "2023-06-16T09:55:36Z")

</div>

Using `rand`s is fine. To be truly identical both branches should consume the same number of rands form the given RNG, and the result should depend on them in the same way, so that the return value is the same.

However, what I probably should have written is “side effects and return value should behave identically, for whatever meaning of `identical behaviour` suits the user”. Most users will be fine with getting a different random sequence when upgrading Julia, and that may happen as a result of upgrading the `Random` package anyways.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [June 16, 2023, 11:47am UTC](https://discourse.julialang.org/t/detect-if-constant/100246/45 "2023-06-16T11:47:01Z")

</div>

That’s not really a tenable definition for how `@constant` is intended to be used though. It’s basically the same as “Do what I mean”, which really isn’t something you can build such a primitive on.

---

<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: [June 16, 2023, 12:40pm UTC](https://discourse.julialang.org/t/detect-if-constant/100246/46 "2023-06-16T12:40:08Z")

</div>

I don’t follow. To me, “do what I mean” is a different concept entirely.

Of course the user is not forced to write code that behaves identically in both branches. Only if the code is expected to behave identically under different versions of Julia is this a requirement.

I can also imagine situations were a user would explicitly violate this principle. For example, let’s say that a piece of code slows down when upgrading Julia, because constant propagation no longer works as expected. Then a test script containing the snippet

```julia
if @constant x
    exit(0)
else
    exit(1)
end

```

might be used in a `git bisect` operation to find the offending commit to the Julia codebase.

---

<div class="post-metadata">

### Author: ![user664303](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/user664303/32/37843_2.png) [@user664303](https://discourse.julialang.org/u/user664303)
#### Post date: [June 16, 2023, 1:56pm UTC](https://discourse.julialang.org/t/detect-if-constant/100246/47 "2023-06-16T13:56:22Z")

</div>

I appreciate all the comments. Thank you.

> [@Benny](#):
>
> The compiler is free to change how it decides constant propagation across versions, so it could select the `@constant` branch in some versions but not the others.

As has been stated by others, in my particular use case the two branches would have identical return types and outcomes/side-effects. From a program perspective, it wouldn’t matter which branch was taken. It would only impact performance. This is the intention of the macro - that it would generally be used to improve performance, not change behaviour.

> [@Sukera](#):
>
> I mean, that sounds like a very hard requirement that’s extremely difficult to check in practice.

We cannot, and I believe need not, enforce this. Like so many other things in the language (abusing `if @generated`, `@inbounds`, etc., as already mentioned), it’s up to the user to do the right thing.

> [@Per](#):
>
> A test script … might be used in a `git bisect` operation to find the offending commit to the Julia codebase.

This is a nice example of how the macro might be sensibly “abused” to achieve something else useful. In the [GitHub feature request](https://github.com/JuliaLang/julia/issues/50176) I also mentioned using the macro in unit tests to test for regressions in constant propagation inference - this seems to be very [unstable](https://github.com/JuliaLang/julia/issues/50073) at the moment. Indeed, @Per 's git bisect suggestion could be used to find the causes of such regressions.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [June 16, 2023, 7:18pm UTC](https://discourse.julialang.org/t/detect-if-constant/100246/48 "2023-06-16T19:18:16Z")

</div>

Perhaps we should call this “optionally propagated constant branches” by this point?

Since this is along the same lines as optionally generated functions with respect to version compilation differences, maybe this should lead to us formally laying out what “same behavior” means in either or both cases. I’m still a little unclear on that here; in most cases you’d want the same return value, but that’s not possible with side effects like `rand`. You might not want to say “same algorithm” either, if we’re allocating different intermediate structures and doing different methods for efficiency. But “same return type and side effects” could easily mean too different a behavior; in the case where there are no side effects, this is just “same return type” which can do completely different things.

Though if you’re testing for regressions, you don’t want “same behavior” there, which should also be documented as acceptable for version testing. Though I would rather a function call profiler tell me what constants are propagated, instead of me manually designing `@constant` branches to test.

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [June 16, 2023, 7:27pm UTC](https://discourse.julialang.org/t/detect-if-constant/100246/49 "2023-06-16T19:27:42Z")

</div>

Yeah I think `if @constant` should behave in direct analogy to optionally generated functions.

This point also raises the possibility of mimicking non-optionally generated functions. We could have something like

```julia
function f(x)
    @constant x begin
        # Generated code using the static value of x
    end 
end

```

which lifts `x` to a `Core.Const` regardless of whether its runtime value is known ahead of time or not, just like using `Val`, but without you needing to write wholly new methods or dispatch chains. So if `x` isn’t constant propagated into that block, you need to do runtime codegen

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [June 16, 2023, 8:12pm UTC](https://discourse.julialang.org/t/detect-if-constant/100246/50 "2023-06-16T20:12:17Z")

</div>

If it’s a direct analogy, then that non-optional `@constant` annotation should really be in the header for clarity. `function f(x)` really shouldn’t indicate a function that generates code depending on the value of `x`. I’m not even comfortable with `function f(@constant x)`, and that doesn’t cover intermediate variables in the body. Maybe we do put something in front like `@generatedconstant function f(x)`.

This idea does seem a lot stranger than the optional version though. The optional version is more intended to be an optimization for callees, but now this can force a non-constant value to be treated as constant in a branch, it’ll happen even with `f(x)` in the global scope. And it seems like the branch has to be dynamically dispatched to in that case, like a inlined function barrier.

[Previous page](https://discourse.julialang.org/t/detect-if-constant/100246.md?page=2)
