# Writing a static function

**URL:** <https://discourse.julialang.org/t/writing-a-static-function/92882>\
**Category:** General Usage\
**Created:** [January 12, 2023, 3:58pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882 "2023-01-12T15:58:35Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![erlebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/erlebach/32/12973_2.png) [@erlebach](https://discourse.julialang.org/u/erlebach)\
**Post date:** [January 12, 2023, 3:58pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/1 "2023-01-12T15:58:35Z")

</div>

Is it possible to write a static function in Julia with functionality similar to that in C++?

```julia
function tst_static()
     static int count = 0
     count = count + 1
     println("count = ", count)
end

for i in [1,2,3]:
    tst_static()
end

```

I would like this code snippet to print `1 2 3` on successive lines. How would one do that? Thanks.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [January 12, 2023, 4:08pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/2 "2023-01-12T16:08:48Z")

</div>

```julia
let count=0
    global tst_static
    function tst_static()
        count += 1
        @show count
    end
end

```

which gives

```julia
julia> for i in 1:3
           tst_static()
       end
count = 1
count = 2
count = 3

```

---

<div class="post-metadata">

**Author:** ![erlebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/erlebach/32/12973_2.png) [@erlebach](https://discourse.julialang.org/u/erlebach)\
**Post date:** [January 12, 2023, 4:17pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/3 "2023-01-12T16:17:28Z")

</div>

Thanks. Now, I will want to use this function as a. Callback function, that will be an argument in some optimizer, see my previous message in this thread.

Gordon

---

<div class="post-metadata">

**Author:** ![erlebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/erlebach/32/12973_2.png) [@erlebach](https://discourse.julialang.org/u/erlebach)\
**Post date:** [January 12, 2023, 8:17pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/4 "2023-01-12T20:17:40Z")

</div>

Could you please explain whether or not `let` can be used inside a function? The following error:

```julia
iter = 0
function global_fct
    let count1=iter
    end
end

```

produces the error:

```julia
ERROR: syntax: expected "end" in definition of function "global_fct"
Stacktrace:
 [1] top-level scope
   @ ~/src/2022/rude/giesekus/MWE_static_function.jl:4

```

What is happening? Thanks.

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [January 12, 2023, 9:01pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/5 "2023-01-12T21:01:05Z")

</div>

You are missing parentheses in the function definition:  
`function global_fct()`

The no-parentheses version can only be written  
`function foo end`  
(hence it complaining about the missing `end`) and is used to define a function but not define any methods. This is common to do for abstract interfaces so that concrete implementations can add methods later.

---

<div class="post-metadata">

**Author:** ![erlebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/erlebach/32/12973_2.png) [@erlebach](https://discourse.julialang.org/u/erlebach)\
**Post date:** [January 12, 2023, 9:52pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/6 "2023-01-12T21:52:18Z")

</div>

@stevengj , your solution with `let` works perfectly. I could not figure out how to use the `let` within an outer function, so I left it in the global space. Not idea, but I could wrap it with a module if necessary.

The next challenge is to have the ability somehow to reset the static variable (which runs counter the notion of static) without restarting the Julia code. That is why including the `let` within a function would have been useful. Is it possible to reset the counter? Perhaps using a structure for this purpose might work? Thanks.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 12, 2023, 10:04pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/7 "2023-01-12T22:04:30Z")

</div>

You could use a functor, for example: [In Julia, how to create a function that saves its own internal state? - #6 by lmiq](https://discourse.julialang.org/t/in-julia-how-to-create-a-function-that-saves-its-own-internal-state/58457/6)

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 12, 2023, 10:36pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/8 "2023-01-12T22:36:01Z")

</div>

This code surprised me 😅 I never realized the possibility.

It’s interesting to me that `count` gets boxed and loses type stability like any global, even though `tst_static` is the only thing that touches it. Adding a type assertion fixes the loss of type stability and improves speed, but it still gets boxed and causes allocations, so is not quite as performant as making a struct/functor or using a `Ref`.

> **Code for benchmarking**
>
> ```julia
> # code variants
> let a=0; global foo() = (a+=1; a) end # local
> let b::Int=0; global bar() = (b += 1; b) end # local w/ type assertion
> c=0; baz() = (global c += 1; c) # global
> d::Int = 0; qux() = (global d += 1; d) # global w/ type assertion
> let e = Ref(0); global fred() = (e[] += 1; e) end # local Ref (avoids reassigning identifier)
> 
> using BenchmarkTools
> @btime foo() # slow
> @btime bar() # faster
> @btime baz() # slow
> @btime qux() # faster
> @btime fred() # fastest (no box, no allocations)
> 
> @code_warntype foo() # type-unstable
> @code_warntype bar() # loses type in box, regains at assertion
> @code_warntype baz() # type-unstable
> @code_warntype qux() # type-stable
> @code_warntype fred() # type-stable
> 
> ```

@erlebach Perhaps something like this?

```julia
let count = Ref(0)
    global function test()
        count[] += 1
        println("count = ", count[])
    end
    global function reset()
        count[] = 0
        println("count reset to ", count[], " successfully!")
    end
end

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [January 12, 2023, 10:53pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/9 "2023-01-12T22:53:41Z")

</div>

> [@lmiq](#):
>
> You could use a functor, for example

For example, a function-call counter:

```julia
mutable struct CallCounter{F} <: Function
    f::F
    count::Int
end
CallCounter(f::F) where {F} = CallCounter{F}(f, 0)
function (c::CallCounter)(args...; kwargs...)
    c.count += 1
    return c.f(args...; kwargs...)
end

```

in which case you can wrap a function in a new `CallCounter` object any time you want to count the number of times it is invoked:

```julia
c = CallCounter(sin)
sum(c, 1:10)
@show c.count

```

which prints `c.count = 10`.

---

<div class="post-metadata">

**Author:** ![erlebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/erlebach/32/12973_2.png) [@erlebach](https://discourse.julialang.org/u/erlebach)\
**Post date:** [January 12, 2023, 11:17pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/10 "2023-01-12T23:17:50Z")

</div>

You all have certainly given me food for thought. I must now ruminate. Thanks!

---

<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:** [January 13, 2023, 12:42am UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/11 "2023-01-13T00:42:16Z")

</div>

> [@erlebach](#):
>
> the ability somehow to reset the static variable

Going off stevengj’s example (but with different names), you just need to make another function to interact with the hidden state (code block below).

Worth mentioning that if you’re planning to have many functions interact with the same state, tying a state to any function via a functor would be tricky; if you have a `add_count = CountIncrementer(0)` instance, `add_count()` could only increment, so resetting has to look like `reset(add_count)` or `add_count(ResetStyle())`. At that point, I’d rather keep the state (reassign a `::Int` variable, mutate a `Ref{Int}`) separate from the functions.

```julia
let count=0
    global add_count # formerly tst_static
    global reset_count
    function add_count()
        count += 1
        count # return instead of `@show`
    end
    function reset_count()
        count = 0
        count
    end
end

```

But personally I think there are better ways of holding state than closures (a reason in next paragraph). This example was a somewhat unusual pattern to get a globally scoped function to capture a temporary (which can’t be global) variable. But there’s no reason that variable has to be temporary. You could make `_count` a type-annotated global variable that `tst_static` increments; I would name it `_count` so it doesn’t collide with the function `Base.count`.

> [@uniment](#):
>
> It’s interesting to me that `count` gets boxed and loses type stability like any global, even though `tst_static` is the only thing that touches it.

The `::Any` inference (and the associated allocations) are not because of the global scope, but because a captured variable is reassigned somewhere. The closure and its surrounding scope don’t run at the same time, so their type inference also happen separately. The surrounding scope cannot unilaterally infer anything about variables it shares with the closure, and by the time the closure runs, the variables are stuck as uninferred. The only ways to possibly patch this are type assertions or never reassigning the variable.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 13, 2023, 4:22am UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/12 "2023-01-13T04:22:10Z")

</div>

> [@Benny](#):
>
> never reassigning the variable

This is why I avoided `count=0` in favor of `count=Ref(0)`—so that instead of reassigning the identifier, we merely `setindex!` a new value into its `x` field to avoid any performance penalty.

The same applies for globals: working with a constant `Ref` is faster than reassigning a type-annotated variable. To illustrate (Julia 1.9.0-alpha1):

```julia
julia> c1::Int = 0
0

julia> const c2 = Ref(0)
Base.RefValue{Int64}(0)

julia> function f1() global c1 += 1 end
f1 (generic function with 1 method)

julia> function f2() global c2[] += 1 end
f2 (generic function with 1 method)

julia> @btime f1()
  11.300 ns (1 allocation: 16 bytes)
500503

julia> @btime f2()
  4.800 ns (0 allocations: 0 bytes)
500503

```

What’s a mild surprise for me, is that part of me thinks the compiler should be able to tell through static analysis that the captured value never changes type. Instead, it sees the function make an assignment and it gives up.

The other mild surprise, is that when I think of a _capture_, I think of a functor whose struct contains its captured values (which can be accessed and manipulated externally, although that’s not official API). For example:

```julia
julia> const foo = let i = Ref(0); f() = (i[] += 1; i[]) end
(::var"#f#1"{Base.RefValue{Int64}}) (generic function with 1 method)

julia> ((foo() for _=1:5)...,)
(1, 2, 3, 4, 5)

julia> foo.i[] = 10;

julia> ((foo() for _=1:5)...,)
(11, 12, 13, 14, 15)

```

By contrast, these global functions are singleton.

```julia
julia> let i = Ref(0); global bar() = (i[] += 1; i[]) end
bar (generic function with 1 method)

julia> ((bar() for _=1:5)...,)
(1, 2, 3, 4, 5)

julia> bar.i[] = 10
ERROR: type #bar has no field i

```

Are these the only state-storing objects in the language whose state is truly private? 🤔

---

<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:** [January 13, 2023, 10:20am UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/13 "2023-01-13T10:20:50Z")

</div>

> [@uniment](#):
>
> What’s a mild surprise for me, is that part of me thinks the compiler should be able to tell through static analysis that the captured value never changes type.

That code example is worth a post by itself. I do agree that there _should_ be enough type information to make `f1` as efficient as `f2`. I wonder if there is some obstacle that I don’t know about or if it’s just that they haven’t implemented typed globals fully yet.

> [@uniment](#):
>
> The other mild surprise … these global functions are singleton…Are these the only state-storing objects in the language whose state is truly private?

I have actually managed to access and mutate such state before, though it escapes me exactly how. Big part was realizing that it was a _method_ that captures the variables; different methods of a function can be defined whenever and capture different outer variables, so the function’s type cannot specify a fixed number of fields for state. So I somehow accessed a method (hidden internal detail, I’m sure) and found a `roots` field that was an array holding the state. But it only worked well for state created in a `let` block, for some reason only symbols for some global variables were stored there.

Capturing variables methodwise seems more flexible, but global functions get to assume they’re a singleton instance, whereas closures are supposed to be many instances holding their own states yet using the same set of methods. Can’t reasonably change the structure of the state in several scattered instances. Closures could be implemented as very similar but separate functions instead, but that’s a lot more to compile.

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [January 13, 2023, 10:58am UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/14 "2023-01-13T10:58:56Z")

</div>

> [@Benny](#):
>
> > [@uniment](#):
> >
> > What’s a mild surprise for me, is that part of me thinks the compiler should be able to tell through static analysis that the captured value never changes type.
> 
> That code example is worth a post by itself. I do agree that there _should_ be enough type information to make `f1` as efficient as `f2`. I wonder if there is some obstacle that I don’t know about or if it’s just that they haven’t implemented typed globals fully yet.

Another instance of [https://github.com/JuliaLang/julia/issues/15276](https://github.com/JuliaLang/julia/issues/15276)?

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 13, 2023, 12:10pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/15 "2023-01-13T12:10:24Z")

</div>

Ha, it’s _[exactly this scenario](https://github.com/JuliaLang/julia/issues/15276#issuecomment-861931378)_.

I don’t see any reason not to parameterize `Core.Box` so that it behaves like `Ref`. As it is now, it generally has worse performance than `Ref` even with type assertions.

---

<div class="post-metadata">

**Author:** ![erlebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/erlebach/32/12973_2.png) [@erlebach](https://discourse.julialang.org/u/erlebach)\
**Post date:** [January 13, 2023, 12:27pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/16 "2023-01-13T12:27:21Z")

</div>

Your approach counts how many times the wrapper is invoked. Cool though.

---

<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:** [January 13, 2023, 12:40pm UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/17 "2023-01-13T12:40:02Z")

</div>

> [@uniment](#):
>
> I don’t see any reason not to parameterize `Core.Box` so that it behaves like `Ref`. As it is now, it generally has worse performance than `Ref` even with type assertions.

This is intentional. You really don’t want to specialize the _compiler_ on every boxed variable. At the same time, you can’t insert type parameters during lowering because types do not exist yet at that point in the compilation process. You’d more or less end up with `Box{Any}` (the same happens when you call a function that returns `Any`, where inference can’t figure it out), leaving you exactly where we are right now.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 14, 2023, 12:48am UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/18 "2023-01-14T00:48:37Z")

</div>

Makes sense, I think.

I’m swimming outside my depth, but it _feels_ like there ought to be a way: because if I can do it, the compiler—which I trust is far more intelligent than I—ought to be able to 😅

I would think that type-annotating a variable that’s going to be boxed, could get syntax-transformed into type-parameterized boxing. We shouldn’t need to know the type; just throw the expression into the curly braces. For example:

```julia
let a::MyType = 0
    () -> (a += 1; a)
end

#= currently transforms into something like this: =#
let a = Core.Box(0)
    () -> (a.contents = a.contents::MyType + 1; a.contents::MyType)
end

#= maybe better to transform into this: =#
let a = Core.Box{MyType}(0)
    () -> (a.contents = a.contents::MyType + 1; a.contents::MyType)
end

```

this is basically what the `Ref` hack amounts to anyway. The type assertions become redundant, but maybe it’s easiest to leave them in, idk.

The compiler makes the decision to box based on analysis of the syntax, without type information, so it feels like a syntax transform (or something equivalent to one) ought to be the fix?

Note: the least invasive change might be like this:

```julia
mutable struct Box{C} contents::C end
Box(contents) = Box{Any}(contents)

```

then, any code that simply calls `Box(x)` doesn’t need to change immediately.

---

<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:** [January 14, 2023, 1:40am UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/19 "2023-01-14T01:40:19Z")

</div>

> [@GunnarFarneback](#):
>
> Another instance of [https://github.com/JuliaLang/julia/issues/15276](https://github.com/JuliaLang/julia/issues/15276)?

I’m not actually sure. I expected at first that reassignment of globals with a fixed type would be implemented without boxing much like mutation of `const` `Ref`s, which `@uniment` demonstrates in `f2()`. But evidently functions do not yet capture the types of typed globals as well as types of `const` variables, and it does seem a lot like the boxing of a typed local variable described in captured variables section at the end of the Performance Tips.

> [@uniment](#):
>
> because if I can do it, the compiler—which I trust is far more intelligent than I—ought to be able to

From what I could gather from the longstanding captured variable issue, it’s more specifically earlier stages in the compilation process making decisions about types before type inference can happen. Someone commented that it would need a redesign of the lowering stage and it would have to happen after rewriting some of the codebase in Julia.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 14, 2023, 4:41am UTC](https://discourse.julialang.org/t/writing-a-static-function/92882/20 "2023-01-14T04:41:18Z")

</div>

> [@Benny](#):
>
> Someone commented that it would need a redesign of the lowering stage

I think [that comment](https://github.com/JuliaLang/julia/issues/15276#issuecomment-922435607) was about type _inference_, since it would need to be known e.g. what type `(+)(::Int, ::Int)` returns. If the variable’s type has been annotated anyway, then inference shouldn’t be needed I would think.

Interestingly, the fact that a variable is captured causes it to be boxed not only for the function that captures it, but also for the scope where it’s defined. Comparison of a) untyped capture, b) type-annotated capture, and c) typed `Ref`:

```julia
julia> using BenchmarkTools

julia> gena() = let a=0; for i=1:1000; a+=i end; ()->a+=1 end
       genb() = let a::Int=0; for i=1:1000; a+=i end; ()->a+=1 end
       genc() = let a=Ref(0); for i=1:1000; a[]+=i end; ()->a[]+=1 end;

julia> @btime gena(); @btime genb(); @btime genc();
  22.900 μs (1459 allocations: 22.80 KiB)
  5.940 μs (970 allocations: 15.16 KiB)
  6.700 ns (1 allocation: 16 bytes)

julia> a, b, c = gena(), genb(), genc()
       a() == b() == c()
true

julia> @btime $a(); @btime $b(); @btime $c();
  27.614 ns (1 allocation: 16 bytes)
  11.735 ns (1 allocation: 16 bytes)
  4.805 ns (0 allocations: 0 bytes)

```

Note `ns` vs `μs` timings for the `gen` functions.

We can confirm our understanding by using `Ref{Any}` to imitate a `Box` and inserting type annotations to mimic the behavior of a type-annotated variable. Comparison of d) mimicking untyped capture, e) mimicking type-annotated capture, and f) typed `Ref`:

```julia
julia> gend() = let a=Ref{Any}(0); for i=1:1000; a[]+=i end; ()->a[]+=1 end
       gene() = let a=Ref{Any}(0); for i=1:1000; a[]=a[]::Int+i end; ()->a[]=a[]::Int+1 end
       genf() = let a=Ref{Int}(0); for i=1:1000; a[]=a[]::Int+i end; ()->a[]=a[]::Int+1 end;

julia> @btime gend(); @btime gene(); @btime genf();
  23.200 μs (1459 allocations: 22.80 KiB)
  6.180 μs (970 allocations: 15.16 KiB)
  6.700 ns (1 allocation: 16 bytes)

julia> d, e, f = gend(), gene(), genf()
       d() == e() == f()
true

julia> @btime $d(); @btime $e(); @btime $f();
  28.313 ns (1 allocation: 16 bytes)
  11.211 ns (1 allocation: 16 bytes)
  4.600 ns (0 allocations: 0 bytes)

```

From this demonstration, it seems reasonably likely that making a type-parameterized `Core.Box` will allow for immediate performance improvements—at least where type annotation is used.

Of course it’d be better for type inference to work in the lowering stage so that we wouldn’t need to make type annotations, but I don’t know what the schedule for that is. Even then, it seems we’d want a type-parameterized `Box` anyway.

[Next page](https://discourse.julialang.org/t/writing-a-static-function/92882.md?page=2)
