Hi,
We have the option run automatically things when Julia starts using the Startup.jl file.
Is there something similar when you exist Julia?
If it does not exist, is it a reasonable feature to ask for?
Or is there a way to do it without asking for a feature request?
Thank you
help?> atexit
atexit(f)
Register a zero- or one-argument function f() to be called at process exit. atexit() hooks are called in last in first out (LIFO) order and run before object finalizers. [..]
[There are also finalizers. I’ve never used them, not sure many do (and thay have a purpose, are helpful at least for for code, NOT when exiting). There are issues on exit, I believe they are still run on exit, but it’s problematic, and I recall an issue about NOT running them. It may not be needed (or may, then getting the change is problematic), e.g. if you want (fast startup and) fast shutdown, like me, then you want to about quickly on exit, not delay by running marginally important code, in that case.]
[And also I want the startup file gone for non-interactive… it shouldn’t be the default, makes code, and compiled apps, if applying there, nondeterministic. Potentially a security issue, if people don’t know what code has been run before the code you intended.]
There is a feature for finalizing mutable structs which can serve to simulate such a feature. Not sure how this is especially useful, but:
julia> mutable struct Test
a::Int
end
julia> t = Test(10)
Test(10)
julia> finalizer(t) do x
println("bye bye")
end
Test(10)
julia> # pressing Ctrl-D (exit) here
bye bye
@gitboy16 Here’s an example (preferred IMHO, why I moved solution check to mine) for the documented way I pointed to:
julia> atexit(x -> println("bye bye"))
julia> # pressing Ctrl-D (exit) here
bye bye
@dan’s example is valid, in at least a different sense. I.e besides it being much verbose to implement, if you do his way, define the variable t, then when t falls out of scope, i.e. in the middle of running the program, somewhere deep in your call stack, then it IS allowed to run the finalizer. In a language like C++ with destructors, it would then run as soon as out of scope, but finalizers depend on garbage collection, and you may need to wait an arbitrary long time.
I was warning against the finalizer solution, since their point is to free up non-memory resources (not anything else I believe, not meant for (other) side-effects, while yes, still possible), and when your program terminates, it’s e.g. not really helpful to free memory one object after another (what the GC usually does), rather just not do it, and let the OS throw it all away. That would also work for closing file handles, while I believe is the main purpose for finalizers (unsure if closed or flushed automatically on exit, but arguably could be flushed; and should be closed in every modern OS). As I wrote running finalizers may stop working in some future Julia version, if deemed an ok trade-off, so I would NOT use it for this, especially since the other documented way works.
Out of curiosity, what do you actually want run at exit? And is it appropriate earlier, i.e using finalizers then?
C# never had destroctors (like the concept defined in C++, it was a misnomer, only the syntax for similar.
There’s precedent to stop running finalizers on exit as C#/.NET did (for performance reasons when exiting, and other issues with it, JuliaLang has an issue on doing same), and you want your program to work the same of that happens:
Finalizers (historically referred to as destructors) […]
[…]
- .NET 5 (including .NET Core) or a later version: There’s no output, because this implementation of .NET doesn’t call finalizers when the application terminates.