Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type Finalizers #1037

Open
Keno opened this issue Jul 11, 2012 · 7 comments
Open

Type Finalizers #1037

Keno opened this issue Jul 11, 2012 · 7 comments
Labels
types and dispatch Types, subtyping and method dispatch

Comments

@Keno
Copy link
Member

Keno commented Jul 11, 2012

Quite often I find myself wanting to associate a finalizer with every object of a given type (particularly to free any associated resources), and even though it is currently possible to call finalizer on every newly created object, but that method strikes as rather inelegant (and perhaps inefficient if the number of objects grows large). Instead I propose to add the ability to have a function applied to all objects of a given type once they are gc'd. I have something like the following in mind:

type SomeType
    #Other field omitted
    resource::Ptr{Void}
end
#Upon destruction the GC makes a lookup to see if such a function exists and if it does calls it
finalize(x::SomeType) = custom_destroy(x.resource)

Now, I'm uncertain as to the performance implication of doing a function lookup whenever an object is destroyed, but given the special nature of such a function, it might be worth thinking about adding an extra field to jl_struct_type_t which would hold the type finalizer (just as it does hold constructors now).

@JeffBezanson
Copy link
Member

Yes, it really couldn't be a method call. We would get a bit of savings by not having to store finalizers per-object. But, this is pretty "featurey".

@StefanKarpinski
Copy link
Member

How about always calling the finalize function on objects when they're GC's but the default implementation is that it does nothing (or looks up a per-object finalizer in the current style)? You could add per-class methods to do something else.

@JeffBezanson
Copy link
Member

No, that is way too slow. And we want to preserve the possiblity of doing GC that is O(1) in the number of dead objects.

@jakebolewski
Copy link
Member

Can this issue be closed?

@Keno
Copy link
Member Author

Keno commented Oct 22, 2014

I'm not sure we have a good solution yet.

@andyferris
Copy link
Member

If we view the finalizer as a static part of the type (like inner constructors) should the method be defined in the type definition?

mutable struct SomeType
    #Other field omitted
    resource::Ptr{Void}

    finalize(x::SomeType) = custom_destroy(x.resource)
end

As suggested, perhaps the pointer to compiled finalize could reside in the type. Not sure how this would interact with the fix to #265 - maybe type finalizers could be treated like @pure functions?

@vtjnash
Copy link
Member

vtjnash commented Sep 28, 2022

doing GC that is O(1) in the number of dead objects

So that seems to limit this to being an implicit (syntactic) feature that alters the lowering of new() calls to also have a call to the existing finalizer function. Thus we could define the syntax, such that:

struct SomeType
    #Other field omitted
    resource::Ptr{Void}
    finalize(x::SomeType) = custom_destroy(x.resource)
end

With the the magic local function name finalize, like new, tha twould change constructor lowering (both implicit and explicit forms) from

SomeType(resource) = new(resource)

to

SomeType(resource) = finalizer(finalize, new(resource))

Is that worth it, or is it time to close this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
types and dispatch Types, subtyping and method dispatch
Projects
None yet
Development

No branches or pull requests

8 participants