# Single-method function as a more re-evaluation-friendly \`const\`?

**URL:** <https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433>\
**Category:** Internals & Design\
**Tags:** repl, development, revise\
**Created:** [August 23, 2020, 9:57pm UTC](https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433 "2020-08-23T21:57:41Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![NHDaly](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nhdaly/32/1413_2.png) [@NHDaly](https://discourse.julialang.org/u/NHDaly)\
**Post date:** [August 23, 2020, 9:57pm UTC](https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433/1 "2020-08-23T21:57:41Z")

</div>

So i was thinking about some of the conversations we had at JuliaCon about Julia’s ability to handle _redefining_ `const` variables, and i was wondering if we should just always prefer to use a single-method function instead of consts, since those play much nicer with Revise and changing them during development?

@oxinabox, @Syx_Pek, @Oscar_Smith, @oschulz and I were talking about julia redefinition and Revise and incrementality, and we reflected on how julia is able to handle redefined methods but not redefined consts. So I’m wondering, then, are there any features that a `const` variable provides that a global function with only a single zero-arg method wouldn’t? Can you use a function with only a single zero-arg method as a replacement that supports live programming?

I know that if a function has more than one method, it can’t always be devirtualized (e.g. if its calling args are type unstable), but can a zero-argument method always be devirtualized and inlined? If its body is literally just a return statement of a literal, is it always available to the compiler just like a `const` is? Or do we need something more to get that, like `@pure`, in which case redefinition / live programming are similarly restricted?

If there are some other requirements to make this work (like the function must have no other methods, and the body must be only a return statement, etc), maybe we could just have a macro that asserts those things?

```julia
julia> @constf x() = 2

julia> f(a) = x() + 1

julia> @constf f() = 3
ERROR: Can't declare f() as a constant function; it has other methods.

```

Or something like that?

---

<div class="post-metadata">

**Author:** ![affans](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/affans/32/11911_2.png) [@affans](https://discourse.julialang.org/u/affans)\
**Post date:** [August 23, 2020, 10:07pm UTC](https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433/2 "2020-08-23T22:07:42Z")

</div>

This is an interesting idea, and I’ve thought of it before. I don’t have the expertise to answer this, but I’ve just avoided this way simply because I think calling a function incurs more overhead than just defining a const.

But we shall wait for the experts to chime in here.

---

<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:** [August 23, 2020, 10:27pm UTC](https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433/3 "2020-08-23T22:27:42Z")

</div>

This is exactly what was used in [GitHub - MasonProtter/ToggleableAsserts.jl: Assertions that can be turned on or off with a switch, with no runtime penalty when they're off.](https://github.com/MasonProtter/ToggleableAsserts.jl) so that things would be recompiled if the assertion flag was flipped.

> [@affans](#):
>
> This is an interesting idea, and I’ve thought of it before. I don’t have the expertise to answer this, but I’ve just avoided this way simply because I think calling a function incurs more overhead than just defining a const.

I’m not an expert, but I guess I’d just say it depends on what you mean by “overhead”. If it’s runtime overhead, the answer is no. If it’s compile time overhead, I’m not so sure. Certainly there is extra overhead from causing functions to be recompiled if you change the `const`, but the alternative is having your functions just not update which doesn’t sound very nice.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [August 24, 2020, 12:59am UTC](https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433/4 "2020-08-24T00:59:58Z")

</div>

Unless you have extremely good reason that the const has to be a constant and you have to mutate it, use a constant ref and mutate that instead. Redefining a function is abusing the system.

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [August 24, 2020, 8:42am UTC](https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433/5 "2020-08-24T08:42:31Z")

</div>

`const Ref` won’t constant fold.  
A constant function will

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [August 24, 2020, 1:15pm UTC](https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433/6 "2020-08-24T13:15:33Z")

</div>

Well, that’s exactly why I said you have to have extremely good reason. Constant folding isn’t a good reason at all. The question is why do you need constant folding.

---

<div class="post-metadata">

**Author:** ![NHDaly](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nhdaly/32/1413_2.png) [@NHDaly](https://discourse.julialang.org/u/NHDaly)\
**Post date:** [August 24, 2020, 2:18pm UTC](https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433/7 "2020-08-24T14:18:25Z")

</div>

Ah, @yuyichao, i should have made it more clear: I’m not talking about modifying it _during execution_, I’m talking about redefining the constant _during development_. The kind of thing that Julia+Revise.jl supports quite well for redefining functions during development, but of course they don’t support redefining a constant.

I completely agree that redefining a function at runtime is abusing the system, but of course redefining a function during development is expected/encouraged. So I was wondering if we would be losing anything by using a zero-arg method instead of a `const` variable, so that it would support redefining _during development_.

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [August 24, 2020, 3:26pm UTC](https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433/8 "2020-08-24T15:26:26Z")

</div>

For fun I tried to benchmark compilation times.

```julia
cvar(i) = Symbol(:const_var_b, i)
cfun(i) = Symbol(:const_fun_b, i)
N = 100

for i in 1:N
@eval const $(cvar(i)) = $i
@eval $(cfun(i))() = $i
end

@eval var_sum() = +($((cvar(i) for i in 1:N)...))
@eval fun_sum() = +($((:($(cfun(i))()) for i in 1:N)...))

julia> @time var_sum() # this result must have a lot of generic JIT warm-up
  0.008526 seconds (8.52 k allocations: 437.659 KiB)
5050

julia> @time fun_sum()
  0.000012 seconds (2 allocations: 832 bytes)
5050

# ... Redo the whole exercise with the `Symbol(:const_var_b, i)` instead of `:const_var`:

julia> @time var_sum()
  0.000008 seconds (2 allocations: 832 bytes)
5050

julia> @time fun_sum()
  0.000011 seconds (2 allocations: 832 bytes)
5050

# Runtimes are equal, as expected

julia> @btime fun_sum()
@bt 1.462 μs (2 allocations: 832 bytes)
5050

julia> @btime var_sum()
  1.464 μs (2 allocations: 832 bytes)
5050

```

FWIW

---

<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:** [August 24, 2020, 7:37pm UTC](https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433/9 "2020-08-24T19:37:03Z")

</div>

> [@NHDaly](#):
>
> Ah, @yuyichao, i should have made it more clear: I’m not talking about modifying it _during execution_ , I’m talking about redefining the constant _during development_ . The kind of thing that Julia+Revise.jl supports quite well for redefining functions during development, but of course they don’t support redefining a constant.

I could be wrong, but I don’t think Yuyichao was talking about runtime redefinitions either.

Redefining a function at runtime wouldn’t see your code recompiling until after you hit the global scope anyways. Functions work within a fixed worldage.

---

<div class="post-metadata">

**Author:** ![NHDaly](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nhdaly/32/1413_2.png) [@NHDaly](https://discourse.julialang.org/u/NHDaly)\
**Post date:** [August 25, 2020, 12:04am UTC](https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433/10 "2020-08-25T00:04:17Z")

</div>

🙂 Yeah, but he mentioned using a const `Ref` as a workaround, which I thought only makes sense in the context of mutating the constant at runtime as part of your program. but maybe I misunderstood!

It doesn’t help with mutating code during development, because e.g. editing the definition of the default value of the Ref would still trigger re-definition. You could I guess update the ref’s value at the REPL (maybe that’s what he meant?) but that’s pretty awkward for the reasons you point out, because you’d certainly not want to use the const Ref in actual production code, so you’d be switching the const to the const Ref at the start of development, and then switching it back.

---

<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:** [August 25, 2020, 12:10am UTC](https://discourse.julialang.org/t/single-method-function-as-a-more-re-evaluation-friendly-const/45433/11 "2020-08-25T00:10:01Z")

</div>

For what it’s worth, I think arguments like “Redefining a function is abusing the system.” are utterly unconvincing and unlikely to change my behaviour unless @yuyichao can at least tell us why ‘abusing the system’ in this way would lead to bad outcomes.

If the only concern is compile times / invalidations I honestly don’t care if it means I can save development time by restarting julia less, or remove runtime overhead of things like assertions.
