.. _finalizers: ========= Finalizer ========= Finalizers are special functions which are called in exactly two cases: ``delete`` is called explicitly on a data type:: var f <- [1,2,3,4] delete f Lambda based iterator or generator is sequenced out:: var src <- [1,2,3,4] var gen <- generator capture (move(src)) ( $ { for ( w in src ) { yield w } return false }) for ( t in gen ) { print("t = {t}\n") } // finalizer is called on captured version of src By default finalizers are called recursively on subtypes. If memory models allows deallocation, standard finalizers also free the memory:: options persistent_heap = true var src <- [1,2,3,4] delete src // memory of src will be freed here Custom finalizers can be defined for any type by overriding the ``finalize`` function. Generic custom finalizers are also allowed:: struct Foo { a : int } def finalize ( var foo : Foo ) { print("we kill foo\n") } var f = Foo(a = 5) delete f // prints 'we kill foo' here -------------------------------- Rules and implementation details -------------------------------- Finalizers obey the following rules: If a custom ``finalize`` is available, it is called instead of default one. Pointer finalizers expand to calling ``finalize`` on the dereferenced pointer, and then calling the native memory finalizer on the result:: var pf = new Foo unsafe { delete pf } This expands to:: def finalize ( var __this:Foo?& explicit -const ) { if ( __this != null ) { _::finalize(deref(__this)) delete /*native*/ __this __this = null } } Static arrays call ``finalize_dim`` generically, which finalizes all its values:: var f : Foo[5] delete f This expands to:: def builtin`finalize_dim ( var a:Foo aka TT[5] explicit ) { for ( aV in a ) { _::finalize(aV) } } Dynamic arrays call ``finalize`` generically, which finalizes all its values:: var f : array delete f This expands to:: def builtin`finalize ( var a:array explicit ) { for ( aV in a ) { _::finalize(aV) } __builtin_array_free(a,4,__context__) } Tables call ``finalize`` generically, which finalizes all its values, but not its keys:: var f : table delete f This expands to:: def builtin`finalize ( var a:table explicit ) { for ( aV in values(a) ) { _::finalize(aV) } __builtin_table_free(a,8,4,__context__) } Custom finalizers are generated for structures. Fields annotated as @do_not_delete are ignored. ``memzero`` clears structure memory at the end:: struct Goo { a : Foo @do_not_delete b : array } var g <- default delete g This expands to:: def finalize ( var __this:Goo explicit ) { _::finalize(__this.a) __::builtin`finalize(__this.b) memzero(__this) } Tuples behave similar to structures. There is no way to ignore individual fields:: var t : tuple delete t This expands to:: def finalize ( var __this:tuple explicit -const ) { _::finalize(__this._0) memzero(__this) } Variants behave similarly to tuples. Only the currently active variant is finalized:: var t : variant> delete t This expands to:: def finalize ( var __this:variant> explicit -const ) { if ( __this is f ) { _::finalize(__this.f) } else if (__this is ai) { __::builtin`finalize(__this.ai) } memzero(__this) } Lambdas and generators have their capture structure finalized. Lambdas can have custom finalizers defined as well (see :ref:`Lambdas `). Classes can define custom finalizers inside the class body (see :ref:`Classes `).