# Functionality like the SAVE statement in Fortran?

**URL:** <https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268>\
**Category:** General Usage\
**Tags:** fortran, functions\
**Created:** [March 23, 2025, 2:43am UTC](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268 "2025-03-23T02:43:46Z")\
**Posts on this page:** 11\
**Page:** 2

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [March 24, 2025, 12:14pm UTC](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268/21 "2025-03-24T12:14:35Z")

</div>

How are the splines represented right now? For that case, it’d make sense to create a `mutable struct Spline` holding all the required data, including a good guess for the interval. From the user perspective, it’d be a matter of defining

```julia
sp = Spline(nodes, values)

```

and then calling evaluations:

```julia
evaluate(sp, x)
evaluate(sp, y)
...

```

---

<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:** [March 24, 2025, 12:17pm UTC](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268/22 "2025-03-24T12:17:53Z")

</div>

Just a my tc here. All these alternatives can at the end be quite confusing for the user, because of the non-transparent handling of the initial approximation, and possible irreproduciblity of a result. I think a simpler way to deal with this would be to just have a struct to carry the data of a fit, and a function to update the fit:

```julia-repl
julia> struct MyFit{T}
           data::Vector{T}
           initial_approximation::Vector{T}
           # other data
       end

julia> MyFit(data::Vector{T}) where {T} = MyFit{T}(data, rand(T,length(data)))
MyFit

julia> function fit!(fit::MyFit)
           x_ini = fit.initial_approximation
           # do stuff and update the fit and the initial approximation
           return fit
       end
fit! (generic function with 1 method)

julia> my_fit = MyFit(rand(10)); # initialize

julia> fit!(my_fit) # fit - updating fit and initial_approximation

julia> fit!(my_fit) # do it again, how many times needed

```

Then you can have multiple instances of fits of different things simultaneously without getting confused. With a callable struct you can also have that, but I don´t see any advantage in terms of user interaction.

With the struct here it is transparent also that the user can copy a `MyFit` object and work with it independently, perhaps updating the data and keeping the initial approximation, and all that is then transparent.

@Vasily_Pisarev beat me by being concise 🙂 . But the struct does not even need to be mutable if the contained data is mutable.

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [March 24, 2025, 2:47pm UTC](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268/23 "2025-03-24T14:47:25Z")

</div>

> [@Mason](#):
>
> ```julia
> function create_counter_func()
> count = AtomicRef(0)
> () -> count[] += 1
> end
> 
> ```

Don’t you need to use `@atomic count.x += 1`? Otherwise, you seem to be inviting data races between the getindex and setindex.

---

<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:** [March 24, 2025, 2:49pm UTC](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268/24 "2025-03-24T14:49:05Z")

</div>

No, that was covered in the `setindex!` and `getindex` methods I defined in the example:

> [@Mason](#):
>
> ```julia
> Base.getindex(r::AtomicRef, order::Symbol=:sequentially_consistent) = @atomic order r.x
> Base.setindex!(r::AtomicRef{T}, x, order::Symbol=:sequentially_consistent) where {T} = @atomic order r.x = convert(T, x)
> 
> ```

If I understand correctly? Maybe not, I dunno, this stuff is underdocumented, and I don’t use atomics much because of things like this.

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [March 24, 2025, 2:52pm UTC](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268/25 "2025-03-24T14:52:22Z")

</div>

I don’t think making the reads and writes separately atomic is sufficient? Admittedly, the atomic API goes a bit over my head, but I imagine the following is still possible with your version:

1. Task 1 reads `tmp1 = count[]`
2. Task 2 reads `tmp2 = count[]`
3. Now `tmp1 == tmp2`
4. Task 1 writes `count[] = tmp1 + 1`
5. Task 2 writes `count[] = tmp2 + 1`

And thus you only incremented the counter by 1, not 2, even though there were two calls.

Note that for atomics, there’s a separate low-level function `modifyproperty!` which is distinct from `setproperty!` and is what `@atomic <some mutating expression>` lowers to: [https://docs.julialang.org/en/v1/base/base/#Base.modifyproperty!](https://docs.julialang.org/en/v1/base/base/#Base.modifyproperty!)

---

<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:** [March 24, 2025, 2:56pm UTC](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268/26 "2025-03-24T14:56:43Z")

</div>

Yes, you are right. This is why I typically just try to avoid stuff like atomics and write algorithms that don’t require one to reason about if there’s a race condition or not.

So I guess that’s part of why an `AtomicRef` hasn’t been provided by base, the `getindex` / `setindex!` interface isn’t sufficient.

I’ve edited my previous comment to not use a `getindex`/`setindex!` pattern.

---

<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:** [March 25, 2025, 2:02am UTC](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268/27 "2025-03-25T02:02:32Z")

</div>

> [@PatrickHaecker](#):
>
> As this occurs so often, wouldn’t it be worth to put this list in the documentation? Somewhere below [Noteworthy differences from C/C++](https://docs.julialang.org/en/v1/manual/noteworthy-differences/#Noteworthy-differences-from-C/C) probably in its own section `Julia ⇔ C/C++: Static Variables`

I would disagree because it could be misinterpreted that these are equivalents to static variables, which is not true. Besides the subtler scoping differences, none of these are static storage. That’s feasible for executables, not interactive processes. For the purpose of a method referencing an object across several calls, closures and global variables (possible encapsulated in a submodule) are reasonable. I personally wouldn’t use vanishing local variables or `@eval` interpolation to reference mutable data like this because that makes reflection much harder.

---

<div class="post-metadata">

**Author:** ![PatrickHaecker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/patrickhaecker/32/222891_2.png) [@PatrickHaecker](https://discourse.julialang.org/u/PatrickHaecker)\
**Post date:** [March 25, 2025, 4:04am UTC](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268/28 "2025-03-25T04:04:54Z")

</div>

> [@Benny](#):
>
> I would disagree because it could be misinterpreted that these are equivalents to static variables, which is not true. Besides the subtler scoping differences, none of these are static storage. That’s feasible for executables, not interactive processes.

I hope that with appropriate wording, we can avoid this misunderstanding now that you have identified it. I can imagine that in at least some approaches, the memory will end up in static memory after (pre)compilation, possibly with `--trim`, if not already, then after future optimizations.

> […] closures and global variables (possible encapsulated in a submodule) are reasonable.

I think we can count the encapsulation in a (sub)module as another option.

Does anyone already know the performance difference between the solutions and which solution needs a `RefValue` for optimum performance? Or do we need to benchmark them?  
The solutions from this thread:

- Closure capturing a local variable
- Local-declared variable inside a top-level begin block
- Global-declared method definition inside a local let block
- A global variable and method in a separate (sub)module
- Interpolate and assign a specific RefValue instance into a globally scoped method definition
- Replace the function with a callable struct

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [March 25, 2025, 1:49pm UTC](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268/29 "2025-03-25T13:49:45Z")

</div>

> [@PatrickHaecker](#):
>
> which solution needs a `RefValue` for optimum performance?

Any approach that captures a variable from an outer scope needs a `Ref` for performance. The principle is that a captured variable should not be reassigned, that is, you should never do `count += 1` if `count` is captured from the enclosing scope; that will force boxing, which kills performance. The `Ref` solves the problem because `count[] += 1` is mutation, not reassignment.

Thus, the following need `Ref` for performance:

- Closure capturing a local variable
- Local-declared variable inside a top-level begin block
- Global-declared method definition inside a local let block
- A global variable and method in a separate (sub)module

The following needs `Ref` to work at all:

- Interpolate and assign a specific RefValue instance into a globally scoped method definition

The following does not need `Ref` (or you could say it replaces the `RefValue` with a dedicated mutable struct—after all, `RefValue` is nothing but a mutable struct with getindex/setindex methods):

- Replace the function with a callable struct

---

<div class="post-metadata">

**Author:** ![PatrickHaecker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/patrickhaecker/32/222891_2.png) [@PatrickHaecker](https://discourse.julialang.org/u/PatrickHaecker)\
**Post date:** [March 25, 2025, 2:09pm UTC](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268/30 "2025-03-25T14:09:33Z")

</div>

Thanks for the explanation and the listing.

I thought from [15276](https://github.com/JuliaLang/julia/issues/15276) that some of the simpler cases are nowadays optimized by the compiler to work without performance penalty without a `RefValue`, too. But that does not seem to be the case.

Some cases like “Local-declared variable inside a top-level begin block” seemed easy to optimize at least if there is nothing else in the begin block besides the local-declared variable and the method, but it is probably more difficult than it seems.

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [March 25, 2025, 2:37pm UTC](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268/31 "2025-03-25T14:37:38Z")

</div>

> [@PatrickHaecker](#):
>
> I thought from [15276](https://github.com/JuliaLang/julia/issues/15276) that some of the simpler cases are nowadays optimized

Looks like there were some cases early on where captured variables were boxed even when only assigned at a single point. See for example [Combo of begin block and return type annotation breaks closure inference · Issue #29326 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/29326). I’d expect those cases to be fixed by now. But if the variable is ever reassigned, I don’t think there’s any hope of it not being boxed in current versions.

[Previous page](https://discourse.julialang.org/t/functionality-like-the-save-statement-in-fortran/127268.md?page=1)
