{"id":13578203,"url":"https://github.com/siffiejoe/lua-finally","last_synced_at":"2025-12-27T15:03:56.602Z","repository":{"id":147352734,"uuid":"47018342","full_name":"siffiejoe/lua-finally","owner":"siffiejoe","description":"Deterministic cleanup of resources in Lua","archived":false,"fork":false,"pushed_at":"2020-07-08T19:43:07.000Z","size":13,"stargazers_count":11,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-05T15:49:30.801Z","etag":null,"topics":["cleanup","lua","raii"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/siffiejoe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2015-11-28T09:52:35.000Z","updated_at":"2024-10-21T18:45:00.000Z","dependencies_parsed_at":"2023-07-02T16:30:57.713Z","dependency_job_id":null,"html_url":"https://github.com/siffiejoe/lua-finally","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siffiejoe%2Flua-finally","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siffiejoe%2Flua-finally/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siffiejoe%2Flua-finally/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siffiejoe%2Flua-finally/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/siffiejoe","download_url":"https://codeload.github.com/siffiejoe/lua-finally/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247366422,"owners_count":20927503,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cleanup","lua","raii"],"created_at":"2024-08-01T15:01:28.394Z","updated_at":"2025-12-27T15:03:51.562Z","avatar_url":"https://github.com/siffiejoe.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"#        Finally -- Deterministic Cleanup of Resources in Lua        #\n\n##                           Introduction                           ##\n\nLua's garbage collector and `__gc` metamethods can handle arbitrary\nresources in a reliable, yet undeterministic way. Some resources\nhowever need to be reclaimed as soon as possible, even if an error is\nraised while using such a resource. Other languages provide dedicated\nlanguage features for this situation (`finally`, `using`, or\nscope-based destruction of objects -- `RAII`). On Lua you can use this\n**finally** module.\n\n\n##                          Getting Started                         ##\n\nThe interface was proposed in a [lua-l mailing list thread][1]: The\n`finally` function takes two Lua functions as arguments, calls the\nfirst, and then the second function even if the first function call\nraises an error (the error is passed as an argument to the second\nfunction call in this case):\n\n    local f1, f2\n    local same = finally( function()\n      f1 = assert( io.open( \"filename1.txt\", \"r\" ) )\n      f2 = assert( io.open( \"filename2.txt\", \"r\" ) )\n      return f1:read( \"*a\" ) == f2:read( \"*a\" )\n    end, function( e )\n      if e then print( \"there was an error!\" ) end\n      if f2 then f2:close() end\n      if f1 then f1:close() end\n    end )\n\nThe `finally` function call returns the results of the first function\n(or re-raises its error) unless an error happens during execution of\nthe second function, in which case previous results/errors are lost.\nThis (and the fact that an interrupted cleanup function could leak\nimportant resources) is the reason why any code that may raise errors\nshould be avoided in the cleanup function. Unfortunately Lua allocates\nsome memory implicitly when running Lua code (e.g. for function call\nframes or the Lua stack), which can cause memory allocation errors or\nerrors in unrelated `__gc` metamethods to be raised. The `finally`\nfunction implementation in this module gives you the chance of writing\ncleanup code that can never be interrupted by calling the cleanup\nfunction in a coroutine (preallocated before the first function call)\nwith reserved call frames and Lua stack slots. Unless you allocate new\nLua values or raise errors explicitly in your cleanup function (or\nwrite faulty Lua code), you are fine.\n\nThe defaults should be good enough for most cleanup code, but you can\npass the number of reserved stack slots (default 100) as the third and\nthe number of preallocated stack frames (default 10) as the fourth\nargument to `finally`. To ensure that the parameters are high enough\nfor your cleanup code, you can pass a `true`ish value as the fifth\nargument to `finally` during development/testing. This will cause\n*any* memory allocation by Lua during the execution of the cleanup\nfunction to raise an error.\n\nAnd that's all.\n\n  [1]:  http://lua-users.org/lists/lua-l/2015-11/msg00270.html\n  [2]:  http://lua-users.org/lists/lua-l/2015-04/msg00423.html\n\n\n##                          Quirks/Gotchas                          ##\n\nThere are many ways to allocate memory in Lua code inadvertently, and\nthus to risk memory allocation errors or errors in `__gc` metamethods\nwhile running the cleanup function. What you should definitely avoid\nis table literals, writes to non-existing table fields, new strings\n(e.g. using string concatenation, by implicit coercions or `tostring`\ncalls, or some C API functions, e.g. `luaL_error` -- string literals\nin Lua code are fine because they are allocated when the chunk is\ncompiled), new Lua functions, coroutines, or userdata.\n\nThis module works for Lua 5.1 (including LuaJIT) up to Lua 5.3, but\nthe code for Lua 5.1 uses recursive Lua function calls instead of C\nfunction calls to preallocate call frames and stack slots. There is a\nseparate limit for C function calls that could cause an error later in\nthe cleanup function, but you should easily be able to rule this out\nduring testing. You also cannot explicitly set the number of stack\nslots to preallocate. For each call frame approximately 15 extra stack\nslots are available. However, the number of stack slots or call frames\nneeded by a JIT-compiled Lua function might differ from the uncompiled\nversion of the same function, and JIT-compilation itself may happen at\nany time and cause memory allocations. Since the LuaJIT code is\nwritten in assembler, it is hard to figure out where exactly memory\nmight be allocated. So when using LuaJIT you are basically on your\nown!\n\n\n##                              Contact                             ##\n\nPhilipp Janda, siffiejoe(a)gmx.net\n\nComments and feedback are always welcome.\n\n\n##                              License                             ##\n\n**finally** is *copyrighted free software* distributed under the MIT\nlicense (the same license as Lua 5.1). The full license text follows:\n\n    finally (c) 2015 Philipp Janda\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsiffiejoe%2Flua-finally","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsiffiejoe%2Flua-finally","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsiffiejoe%2Flua-finally/lists"}