# Finalizer only works with mutable structs?

**URL:** <https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777>\
**Category:** General Usage\
**Created:** [September 15, 2019, 1:47am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777 "2019-09-15T01:47:50Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [September 15, 2019, 1:47am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/1 "2019-09-15T01:47:50Z")

</div>

The `finalizer` function has the following doc string:

> finalizer(f, x)
> 
> Register a function f(x) to be called when there are no program-accessible references to x, and return x. The type of x must be a mutable struct, otherwise the behavior of this function is unpredictable.

My question are:

1. Why does it work with mutable objects only?

2. How do we register a finalizer for immutable objects?

---

<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:** [September 15, 2019, 2:39am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/2 "2019-09-15T02:39:38Z")

</div>

Because an immutable object doesn’t have lifetime. Semantically, all the objects that has the same “value” are indistinguishable from each other so unless the compiler can proof that a certain value will never ever appear again in the program, it’s never dead and the finalizer must never be called.

> [@tk3369](#):
>
> How do we register a finalizer for immutable objects?

It’s impossible.

---

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [September 15, 2019, 5:12am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/3 "2019-09-15T05:12:04Z")

</div>

> [@yuyichao](#):
>
> Because an immutable object doesn’t have lifetime.

I must be missing something fundamental here. I thought all objects have a lifetime – it can be collected by the garbage collector when it’s no longer being referenced. Is that not true?

More practically, if I create an immutable object that contains an external resource (e.g. an opened file handle) then what can I do to guarantee that the resource is released during GC?

---

<div class="post-metadata">

**Author:** ![mlhetland](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mlhetland/32/283_2.png) [@mlhetland](https://discourse.julialang.org/u/mlhetland)\
**Post date:** [September 15, 2019, 5:50am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/4 "2019-09-15T05:50:02Z")

</div>

No, immutable structs have value semantics, and have no more of a lifetime than, say, an Int. As for the resource question, the answer would be, “you can’t” … as far as I know, the only way would be to make your struct mutable, so it will actually have an identity (and therefore a lifetime), not just a value.

---

<div class="post-metadata">

**Author:** ![mlhetland](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mlhetland/32/283_2.png) [@mlhetland](https://discourse.julialang.org/u/mlhetland)\
**Post date:** [September 15, 2019, 5:54am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/5 "2019-09-15T05:54:17Z")

</div>

(Not saying that they can’t be implemented by heap allocation, but … that’s a different matter.)

---

<div class="post-metadata">

**Author:** ![leethargo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/leethargo/32/6004_2.png) [@leethargo](https://discourse.julialang.org/u/leethargo)\
**Post date:** [September 15, 2019, 8:16am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/6 "2019-09-15T08:16:29Z")

</div>

I found that I also need to use `mutable struct` whenever I want to to use `pointer_to_objref` with an object (because this is passed through a callback function of a C library).

---

<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:** [September 15, 2019, 10:58am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/7 "2019-09-15T10:58:29Z")

</div>

> [@tk3369](#):
>
> How do we register a finalizer for immutable objects?

One option is to add a mutable field, e,g a `Ref`;  
or a pointer `Ptr` then attach the finalizer to that.

The fact that you have something to do in the finalizer suggest you might already have such a field.  
Since finalizers are most useful for cleaning up e.g open handles of versious kinds.  
But sometimes you don’t because somethings things are weird.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [September 15, 2019, 11:05am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/8 "2019-09-15T11:05:45Z")

</div>

> [@tk3369](#):
>
> I must be missing something fundamental here. I thought all objects have a lifetime – it can be collected by the garbage collector when it’s no longer being referenced. Is that not true?
> 
> More practically, if I create an immutable object that contains an external resource (e.g. an opened file handle) then what can I do to guarantee that the resource is released during GC?

It is useful to think about three kinds of objects: Bitstype, immutable non-bitstype and mutable. Then there are two storage modalities: Heap-allocated objects with type header, and deconstructed. Deconstructed objects have no well-defined memory layout (e.g. splattered over multiple registers), but the compiler/runtime fakes (“architects”) the expected layout whenever you look, similar to how the superscalar CPU invents a plausible state it could have been, whenever you look.

@yuyichao talks about “julia architecture”, where immutable objects indeed have no lifetime or address. In “julia uarch”, many immutable non-bitstypes are indeed heap-allocated objects with proper header and lifetime. We want to keep open the possibility of non-breaking compiler improvements that remove allocations for many such objects, which is why we don’t allow pointer\_from\_objref or finalizers.

---

<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:** [September 15, 2019, 11:06am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/9 "2019-09-15T11:06:23Z")

</div>

> [@tk3369](#):
>
> I thought all objects have a lifetime – it can be collected by the garbage collector when it’s no longer being referenced. Is that not true?

That’s not true. All **ALLOCATIONS** have a lifetime. That allocation may or may not have anthing to do with the object. It might not happen at the same time the object is created in the code (it may not even happen) and may or may not end at the same time as the object. This is especially true for immutables and could also be true for mutables.

> [@leethargo](#):
>
> I want to to use `pointer_to_objref` with an object (because this is passed through a callback function of a C library).

Pass the object using `Any` or a correct `Ref` argument type directly. You almost never want to call `pointer_to_objref` yourself. (If you are calling it, you are likely doing it wrong for mutable types as well)

> [@oxinabox](#):
>
> One option is to add a mutable field, e,g a `Ref` , or a pointer `Ptr` then attach the finalizer to that.

Depending on what you mean here.

1. `Ptr` isnt mutable and `Ref` is an abstract type (neither mutable or immutable).
2. If you mean that adding finalizer to a field of an object for tracking the lifetime of the parent object, then it won’t work. If you make sure that the thing you finalize is limited to that mutable field though it’ll of course work.

---

<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:** [September 15, 2019, 11:07am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/10 "2019-09-15T11:07:41Z")

</div>

> [@foobar\_lv2](#):
>
> “julia architecture”, where immutable objects indeed have no lifetime or address. In “julia uarch”, many immutable non-bitstypes are indeed heap-allocated objects with proper header and lifetime.

I think I usually say semantics and implementation… =P.

Anyway, that’s pretty accurate…

---

<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:** [September 15, 2019, 11:27am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/11 "2019-09-15T11:27:16Z")

</div>

> [@yuyichao](#):
>
> > One option is to add a mutable field, e,g a `Ref` , or a pointer `Ptr` then attach the finalizer to that.
> 
> Depending on what you mean here.
> 
> 1. `Ptr` isnt mutable and `Ref` is an abstract type (neither mutable or immutable).

I guess i should have used a semi-colon.

Sure, `Ptr` isn’t mutable but finalizers alway work on pointers. (I am surprised thsis isn’t in the docstring).  
When I said `Ref` I technically ment `RefValue`, but since that isn’t exported, and ref is the exported supertyope that constructs `RefValues` I thought that would be understandable.  
I guess `Base.RefValue` might be clearer, so I guess I will say th.

> 1. If you mean that adding finalizer to a field of an object for tracking the lifetime of the parent object, then it won’t work. If you make sure that the thing you finalize is limited to that mutable field though it’ll of course work.

Yes, either a a dummy object just for purpose tracking this,  
(or something that cleansup only itself, like what handles should do)

```julia
struct Foo
  ...
  _dummy = Base.RefValue{Nothing}
  function Foo(...)
      ...
     dummy = Ref(nothing)
     finalizers(dummy) do
        ...
     end
         
     return new(..., dummy)
  end
end

```

---

<div class="post-metadata">

**Author:** ![cshenton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshenton/32/9326_2.png) [@cshenton](https://discourse.julialang.org/u/cshenton)\
**Post date:** [September 15, 2019, 11:31am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/12 "2019-09-15T11:31:24Z")

</div>

Stack allocated immutables do have a “lifetime” in the sense that they live until the precise moment they fall out of scope. I often find myself wanting to define such C++ style finalisers on C api resource handlers for C++ style resource management.

Am I correct that the only available open for this type of management at the moment is a `do` block?

---

<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:** [September 15, 2019, 11:36am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/13 "2019-09-15T11:36:45Z")

</div>

> [@oxinabox](#):
>
> Sure, `Ptr` isn’t mutable but finalizers alway work on pointers. (I am surprised thsis isn’t in the docstring).

What do you mean? You can’t register a finalizer on a `Ptr`.

> [@oxinabox](#):
>
> Yes, either a a dummy object just for purpose tracking this,

What I was talking about is that you need to make sure your callback **do not** clean up the anything other than `dummy`, which seems to be nothing. Doing this while trying to clean up the actuall `Foo` object is wrong.

---

<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:** [September 15, 2019, 11:39am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/14 "2019-09-15T11:39:05Z")

</div>

> [@cshenton](#):
>
> Stack allocated immutables do have a “lifetime” in the sense that they live until the precise moment they fall out of scope. I often find myself wanting to define such C++ style finalisers on C api resource handlers for C++ style resource management.

All **variables** have a **scope**. That has nothing to do with the lifetime of the variables they refer to. This scope is indeed independent of the type of the object (since it’s not even a property of the object). There’s no scope callback in the language.

> [@cshenton](#):
>
> Am I correct that the only available open for this type of management at the moment is a `do` block?

`do` blocks does not provide any features that you couldn’t do without it. The only way to do this is the `finally` block, which has a pretty high overhead.

---

<div class="post-metadata">

**Author:** ![leethargo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/leethargo/32/6004_2.png) [@leethargo](https://discourse.julialang.org/u/leethargo)\
**Post date:** [September 15, 2019, 11:44am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/15 "2019-09-15T11:44:59Z")

</div>

> [@yuyichao](#):
>
> Pass the object using `Any` or a correct `Ref` argument type directly. You almost never want to call `pointer_to_objref` yourself. (If you are calling it, you are likely doing it wrong for mutable types as well)

Would that make any difference if I then go on to `unsafe_pointer_to_objref` on the result?  
I would like to learn more about the “right way” for my use case, where the C library will not look at the data at all, and simply provide the pointer back to the callback function as `void*`.  
But I fear this it off-topic here.

---

<div class="post-metadata">

**Author:** ![cshenton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshenton/32/9326_2.png) [@cshenton](https://discourse.julialang.org/u/cshenton)\
**Post date:** [September 15, 2019, 11:45am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/16 "2019-09-15T11:45:30Z")

</div>

I think scope callbacks would be great, for the same reason c++ destructors are. However they’d also need to be triggered on variable reassignment in Julia (which I think isn’t the case by default in C++, though you can overload reassignment to destruct first).

I’m aware do blocks are just syntactic sugar, my challenge is more providing a safe API for users to interact with something like Vulkan that is a bit forgiving if they don’t explicitly call destructors on a bunch of objects. Do block is the best API we have for that currently, an even better API would be an automatic destructor.

---

<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:** [September 15, 2019, 11:47am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/17 "2019-09-15T11:47:02Z")

</div>

> [@leethargo](#):
>
> Would that make any difference if I then go on to `unsafe_pointer_to_objref` on the result?

No. The point is that if you are calling it manually and not doing anything else, the compiler can just give you a garbage pointer since your object might be unused as far as the compiler can tell.

> [@leethargo](#):
>
> I would like to learn more about the “right way” for my use case, where the C library will not look at the data at all, and simply provide the pointer back to the callback function as `void*` .

As I said, you can just use the `ccall` argument conversion.

---

<div class="post-metadata">

**Author:** ![leethargo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/leethargo/32/6004_2.png) [@leethargo](https://discourse.julialang.org/u/leethargo)\
**Post date:** [September 15, 2019, 11:49am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/18 "2019-09-15T11:49:19Z")

</div>

> [@yuyichao](#):
>
> The point is that if you are calling it manually and not doing anything else, the compiler can just give you a garbage pointer since your object might be unused as far as the compiler can tell.

So your point is about GC-safety?  
Since the object needs to survive beyond the `ccall` to `submit_callback_function`, I’m already storing a reference separately. It’s just that I can’t access that reference from the callback function.

---

<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:** [September 15, 2019, 11:53am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/19 "2019-09-15T11:53:40Z")

</div>

> [@cshenton](#):
>
> I think scope callbacks would be great, for the same reason c++ destructors are. However they’d also need to be triggered on variable reassignment in Julia (which I think isn’t the case by default in C++, though you can overload reassignment to destruct first).

Triggering on scope exit is OK but it needs a better implementation than finalizers (we actually have that in C…) Triggering on assignment could be pretty bad since it can mess up a lot of the existing macros/lowering that generally assume assigning to temperary variables are insignificant.

> [@leethargo](#):
>
> So your point is about GC-safety?

Yes.

> [@leethargo](#):
>
> Since the object needs to survive beyond the `ccall` to `submit_callback_function` , I’m already storing a reference separately. It’s just that I can’t access that reference from the callback function.

If you are sure the lifetime of that storage is longer than the duration you are going to use it then it’s fine. To be fully generic and support immutable type though, you could still use the `ccall` argument conversion for `Ref{Any}` instead.

---

<div class="post-metadata">

**Author:** ![leethargo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/leethargo/32/6004_2.png) [@leethargo](https://discourse.julialang.org/u/leethargo)\
**Post date:** [September 15, 2019, 11:54am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/20 "2019-09-15T11:54:30Z")

</div>

Thanks for clearing that up!

[Next page](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777.md?page=2)
