lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Wed, Jun 24, 2020 at 1:02 PM Lorenzo Donati
<> wrote:
> On 24/06/2020 03:43, Gé Weijers wrote:
> > The behavior of os.exit is in my opinion a bit inconsistent, it
> > unwinds the stack and closes to-be-closed variables in the main
> > thread, but only if you call it from that main thread, and it does
> > not do anything to other coroutines.
> I wonder whether the whole mechanism is amenable of improvement in these
> areas (i.e. guaranteed closing despite any mechanism that makes a
> program terminate in orderly fashion) or there is a fundamental flaw in
> the design that makes it impossible to handle some specific cases.

You must not forget os.exit calls exit, and exit is a big hammer.

You do not normally call exit(3) on a heavily threaded program or from
deep within a call stack, unless you want problems, it is normally
done as a civilized abort.

> Although I've always wanted a clean, language-supported way to do RAII
> in Lua, I'm still quite unsure if the current mechanism, as it is now,
> is worth the hassle.

Look at the RAII poster child. C++. If you call os.exit it makes some
cleanups, but does not destroy automatic storage duration objects (
which IMHO are the most similar to lua toclose ones ). It closes some
things, destroys automatics ( which may be similar to lua __gc on
globals, which IIRC is invoked ), and goes out. And toclose is not
RAII, is try-with-resources, which AFAIK is what is normally done to
approach RAII in garbage-collected languages, when realizing not all
resources are as easy as memory.

> I didn't follow the 5.4 development closely, but it seems that the
> mechanism doesn't provide unique features. I mean, you can still do RAII
> without it, it just needs more programming discipline.

You can approach RAII. And you can perfectly manage resources in
assembler, C++ compilers do it. But the point on RAII is freeing you
from too much programming discipline, insuring that
"do_database_stuff(create_database_connection())" and similar stuff
just work. If you try to do it by adding a destroy() method to every
"object" you use and carefully using pcall anywhere you can get an
error, and adding destroy() calls everywhere,  you do not gain much
clarity, it's better to seek other ways.

I really do not use os.exit, all my lua is embeded, but it should not
be to difficult to dessign your objects in a way that they are
destroyed ( just overrwrite os.exit, add some atexit() support, do
something like having and idempotent destroy method, make your objects
register in a table for atexit, make __close call destroy and
deregister them, maybe use some handle idiom for easier clearing,

> The whole point of the mechanism, as I see it, is that you could do RAII
> in a much simpler way. But if it introduces other, subtler, issues then
> I'm beginning to question its usefulness.

Use it like try-with-resources, for things which need to be cleaned
when the program errors and unwinds, keep using resources which need
to be properly cleaned on os.exit in other way, it doesn't have to
solve all the problems, and it manages to solve some of them.

> To be clearer: now (Lua 5.3) I can do RAII using more discipline and
> sprinkling error handling code in key parts of the code. This approach
> adds clutter to the code but the error handling code is explicit and clear.

That is because it is not RAII, the point of RAII is AVOIDING the sprinkling.

> In 5.4 I could reduce clutter by using TBC vars, but then I must add
> some extra checks or mechanism to handle those exceptional cases when
> TBC vars mechanism "fails" (and coroutine users are especially worse
> off, it seems). Moreover, the new syntax is not that great.

You do not need to add. Move what you want to TBC, keep the rest as is.

> All in all, I'm starting to think that the mechanism is not
> well-polished yet. At least not enough to warrant a shift of paradigm.
> But maybe I'm missing something.

IMNSHO, you'll never be able to have RAII in a language like lua,
Java, etc.. where ( ignoring lua strings, number, ... ) everything is
a pointer in disguise and you cannot have value objects and it is
relying on garbage collection ( i.e., in perl every "object" is
typically a hash, managed with a pointer in disguise, but the scalar
variables where you store them have ref-counting semantics, so you
have something like C++ but you only are allowed to use make_shared()
to create objects and shared_ptr to ref them ( it has its own problems
with cycles, as C++ ) ).

I've found garbage collection is typically great when you must do
complex memory only structures, not that much elsewhere. I've till now
been fortunate to be able to put this kind of things in arenas when I
have to use them in C++, so no need to use Boehms or similar things.
But for "heavy" resources, I rely on RAII, potentially with
shared_ptrs, and I never, never, use std::exit from deep down, I just
raise my exit_exception and catch it in main().

Francisco Olarte.