# Definition of struct written from C and read-only in Julia

**URL:** <https://discourse.julialang.org/t/definition-of-struct-written-from-c-and-read-only-in-julia/106667>\
**Category:** General Usage\
**Tags:** struct, c\
**Created:** [November 24, 2023, 9:19am UTC](https://discourse.julialang.org/t/definition-of-struct-written-from-c-and-read-only-in-julia/106667 "2023-11-24T09:19:42Z")\
**Posts on this page:** 8\
**Page:** 1

<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:** [November 24, 2023, 9:19am UTC](https://discourse.julialang.org/t/definition-of-struct-written-from-c-and-read-only-in-julia/106667/1 "2023-11-24T09:19:42Z")

</div>

I hand over a struct to a C library which periodically will enter values in the struct’s field and then call a Julia callback function. The struct is defined and gets created (memory allocated) in Julia, but only C writes to it and Julia should never write into that memory during regular program execution. The struct is provided to C as a Ref and received from C as a Ptr. The struct’s fields are (at least currently) only primitive types.

I wonder, what the correct definition in Julia is. If my reading of the [documentation](https://docs.julialang.org/en/v1/manual/types/#Mutable-Composite-Types) is correct, the struct must be defined **mutable** to guarantee a stable memory address, although the values should not be modified in Julia.

As the struct is mutable, from a user’s perspective it seems to be correct to at least declare all fields as **const** to see if some code accidentally tries to write into the fields in Julia. However, is it correct? Or is Julia then allowed to do some optimizations assuming the field values will never change while C is sneaking in modifications behind Julia’s back?

I other words: What combination of **mutable** and **const** is the right choice and are there further options to solve the problem?

---

<div class="post-metadata">

**Author:** ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)\
**Post date:** [November 24, 2023, 9:28am UTC](https://discourse.julialang.org/t/definition-of-struct-written-from-c-and-read-only-in-julia/106667/2 "2023-11-24T09:28:50Z")

</div>

If you make a field `const` in Julia it might land on the stack again, which is what you want to avoid. I think it should all be mutable.

You could instead overwrite `setproperty!` to avoid that generic Julia code accidentally changes some fields. But it is also in pure Julia settings often the case that users should never directly change fields, e.g. maybe just a bit of documentation + giving the users all access via functions in Julia could be sufficient.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [November 24, 2023, 3:08pm UTC](https://discourse.julialang.org/t/definition-of-struct-written-from-c-and-read-only-in-julia/106667/3 "2023-11-24T15:08:27Z")

</div>

Even though the struct itself is immutable, the Ref to it is mutable a d has a stable address.

```julia-repl
julia> struct Foo
           a::Int
           b::Float64
       end

julia> rfoo = Ref(Foo(2, 3.5))
Base.RefValue{Foo}(Foo(2, 3.5))

julia> function bar(ptr::Ptr{Nothing})::Int8
           a_ptr = Ptr{Int}(ptr)
           b_ptr = Ptr{Float64}(ptr + 8)
           unsafe_store!(a_ptr, 9)
           unsafe_store!(b_ptr, 5.6)
           return 0
       end
bar (generic function with 1 method)

julia> bar_ptr = @cfunction(bar, Int8, (Ptr{Nothing},))
Ptr{Nothing} @0x0000007d5c2ad7a0

julia> @ccall $bar_ptr(rfoo::Ref{Foo})::Int
0

julia> rfoo[]
Foo(9, 5.6)

```

---

<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:** [November 24, 2023, 3:30pm UTC](https://discourse.julialang.org/t/definition-of-struct-written-from-c-and-read-only-in-julia/106667/4 "2023-11-24T15:30:39Z")

</div>

> [@mkitti](#):
>
> Even though the struct itself is immutable, the Ref to it is mutable a d has a stable address.

That’s interesting. And, if I may add, calling the self-generated C-compatible function pointer via `@ccall` is really clever.

However, is it guaranteed to work in general? Your example obviously works, but I read the [documentation](https://docs.julialang.org/en/v1/manual/types/)

> in some cases the compiler is able to avoid allocating immutable objects entirely

and

> In order to support mutation, such objects [mutable structs] are generally allocated on the heap, and have stable memory addresses.

such that although unmutable structs can have stable addresses (as in your example), depending on (unspecified) circumstances this is not guaranteed. But the documentation might be imprecise or my reading faulty.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [November 24, 2023, 5:50pm UTC](https://discourse.julialang.org/t/definition-of-struct-written-from-c-and-read-only-in-julia/106667/5 "2023-11-24T17:50:04Z")

</div>

You are focusing on the immutable struct, which in this case is also a bitstype. Basically, it is a compound primitive. However, the operable type here is the `Ref`, concretely a `Base.RefValue{Foo}`.

This could basically be defined as follows.

```julia
mutable struct MyRef{T}
    x::T
end
Base.getindex(mr::MyRef) = mr.x

```

Constructing a `MyRef` results in an allocation.

```julia
julia> @time mr = MyRef(5)
  0.000004 seconds (1 allocation: 16 bytes)
MyRef{Int64}(5)

julia> mr[]
5

```

`MyRef` also thus has a defined location on the heap.

```julia
julia> @time myref = MyRef(Foo(3, 4.5))
  0.000003 seconds (1 allocation: 32 bytes)
MyRef{Foo}(Foo(3, 4.5))

julia> pointer_from_objref(myref)
Ptr{Nothing} @0x0000007d73bc76b0

julia> pointer_from_objref(myref)
Ptr{Nothing} @0x0000007d73bc76b0

```

The pointer is thus to the mutable `Base.RefValue{Foo}`. Because `Foo` is stored inline as a bitstype, we can access Foo’s fields by dereferencing the reference.

There is not an inconsistency in the documentation. An instance of `Foo` does not have a defined address, but a `Base.RefValue{Foo}` does.

---

<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:** [November 27, 2023, 9:55am UTC](https://discourse.julialang.org/t/definition-of-struct-written-from-c-and-read-only-in-julia/106667/6 "2023-11-27T09:55:03Z")

</div>

> [@mkitti](#):
>
> `@time myref = MyRef(Foo(3, 4.5))`

Ahh, thanks @mkitti that was very enlightening. So as long as the instance of the possibly immutable struct is wrapped into a Ref in a `@ccall` (which is recommended in the [documentation](https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#When-to-use-T,-Ptr%7BT%7D-and-Ref%7BT%7D)), C will always get the correct address, because the struct’s address is identical to the Ref’s address and the latter one is always defined (as mentioned in [Ref’s documentation](https://docs.julialang.org/en/v1/base/c/#Core.Ref)).

So I understood: The address is not the limiting factor.

Putting that aside: Telling Julia (or the user) that it’s immutable (or const) while values get constantly changed by the C library is still not a good idea or is it?

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [November 27, 2023, 10:42am UTC](https://discourse.julialang.org/t/definition-of-struct-written-from-c-and-read-only-in-julia/106667/7 "2023-11-27T10:42:53Z")

</div>

If the Julia user is accessing an “immutable” struct via the `Ref` then things should be fine. The `Ref` is mutable and the compiler will not assume that the `Ref` is always pointing to the same struct instance.

The potential danger of mutating something that should not be mutated is that the compiler may incorrectly assume that the value cannot change. However, if you have it contained within a `Ref` there is no problem.

---

<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:** [November 27, 2023, 10:57am UTC](https://discourse.julialang.org/t/definition-of-struct-written-from-c-and-read-only-in-julia/106667/8 "2023-11-27T10:57:45Z")

</div>

Thanks again @mkitti . As the current interface is to not put everything behind a Ref in Julia (only for C), the struct should be mutable with non-const fields.

But good to know that we could change that in the future if need arises, with both changes (Ref + immutable) done in parallel.
