[Date Prev][Date Next][Thread Prev][Thread Next]
- Subject: Re: RFE: refman - adding mention of os.exit not closing variables with default arguments.
- From: Francisco Olarte <folarte@...>
- Date: Wed, 24 Jun 2020 20:09:40 +0200
On Wed, Jun 24, 2020 at 5:29 PM Lorenzo Donati
> I'm no big expert of multithreading, either cooperative or preemptive,
> and I use C only to a limited extent.
> However I thought C's `exit` was the right way to exit a program
> (possibly together with `atexit` mechanism) if returning from main is
> too cumbersome.
Well, C exit jumps out of the call stack and kills your process.
stdlib manages to have your FILE * flushed, OS frees your mem and
handles. But if you need to do cleanup things like status saving, you
need atexit. You use that when returning from main is cumbersome, but
normally you have some other methods ( like killing an event loop or
some thing like that )
> At least C's standard seems to think so:
You notice this is a local reference ( windowish? ) to a file in your
machine? ( I now cpp reference tells that, and know it is a somehow
non leaking way to exit, but in complex programas your transactions
will not get commited and things like dat ).
> I admit I've no experience with C big programs (say 5kLOC+; especially
> multithreaded/GUI ones), so I don't know what's current practice.
It depends on the libs you use, many give you some ways for easier
exiting, or register their own cleanup handlers, but exit is really
> > 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.
> You are right! I just checked here:
> In C++ std::exit doesn't unwind the stack. I didn't know that!
exit never unwinds the stack its purpose is exactly exiting without unwinding.
> About year 2000 I had been using C++ intensively for about 3 years and
> never stumbled on that info. Mostly was number-crunching, data analysis
> and offline simulation of TLC systems, so no interactive stuff.
Those are generally easy on the resource side, I worked on those
things a lot and you normally could even abort.
> > 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 don't follow you here. Why do you say it is not RAII? To me RAIIin C++
> is when you create a local object whose ctor allocates resources and
> whose destructor deallocates them when the object goes out of scope or
> the stack unwinds (returns, exceptions), thanks to C++ semantics.
RAII in C++ means the moment a constructor get executed the destructor
will be called unless you've taken the precaution of using new.
You do not have to store the var in an especial construct, you can
also create it in a temporary expression, i.e., in C++ you can do
And the intermediate db_connection, query, resultset objects, if
appropiately managed, will vanish and be properly closed ( for these
things you need move semantics or advanced classes, in old school C++
you would propably have something like
The thing is you do not have special toclose because you have value
objects, while in java/lua all your objects go into the free store,
you always use somethign like new. So you need syntax to manage them (
try/finally is not a language feature, it is a neccessity, java needs
that, C++ does not. Try with resources is try-finally on steroids. Lua
to-close is very similar to Java try with resources )
In C++ you can create a db connection or get a pointer to an allocated
one. How do you it dictates your management style. In Java or Lua you
always get a pointer, so you need toclose and try with resources if
you want local lifetime management.
> Apart from not there being an exact parallel, because of different
> mechanisms and semantics, it seems Lua TBC vars are just a way to
> conceptually do RAII, i.e. deterministic automatic release of resources.
They are a safer and more elegant way to do a try-finally.
> The key point being the resource release handler (__close metamethod) is
> defined upfront when you acquire the resource, and not lexically scoped
> as a catch block at the end.
That's just sugar, but yes, and sugar is important.
> Am I missing something about what you are saying?
Once you have a destruction and an initialization method, call the
dtor __gc, __close, close, destroy or ~object, you can strictly say
you are doing RAII.
But using RAII in languages without proper scope tracking of values is
a PITA. You get help with TWR, toclose, but you do not get the same
easy code as you have with C++. In C++ you have to explicitly ask for
a dynamically allocated object via new ( or indirectly ) to be able to
foget destroying it. In Java/lua you have to explicitly mark it via
toclose or rely on the garbage collector with its problems.
And the problem with exit is orthogonal to this. It's Thor's retun hammer.
> You are right. My bad. I didn't mean to write RAII. I used RAII here to
> mean "correct release of resources even on error conditions".
That's correct code. It can be done in nearly any language (some of
them bomb out, but they are rare)
> Again, here I lost you. What's the problem about objects not being on
> the stack but being references? TBC vars have been created just for
> that. I agree the semantics is not the same as C++, but the general idea
> is the same:
> 1. (C++): Allocate a local object X of a class with a CTOR that
> allocates the resources you need.
> 1. (Lua): Create a local TB vars that refers to an object X with a
> __close metamethod that allocates the resource you need.
C++ - declare the var, do not use new.
Lua - remember to use a to close.
What happens if you want the resource holding object just to pass it
to a method?
C++ - create it in the parm. list as you would for a var.
Lua - Create a to close, and potentially a block, for the sole purpose
of holding the reg around the call.
> With TBC vars GC doesn't come into play, if I got it right.
> Am I missing something?
No, you can do RAII in any language, it's just painful in some of
them, because you need to explicitly track them.
You cannot put <toclose> in a parameter list.
Also, you have no easy way to see how to track ownership ( i.e.,
imagine you need something fro share ownership. It can be done easily
passing shared__ptrs by value in C++, but althoguh shared_ptrs can be
easily done in lua via some ref-counting or linking and creative
__index manipulation they soon become cumbersome. You can get cleaner
code with toclose, but it is very limited because yo have to mark
every ownership point with local <toclose>.
The problem is I associate RAII with proper value objects, and I mix
it a bit. Nearly everything which you can do in C++ can be done with
creative use of toclose and scopes, but it will get complicated. I.e.,
to do something like filecopy(ofstream("dest"),ofstream("source"))"
you'll need to add a couple of local-toclose for the temporaries, plus
a do-end to avoid namespace pollution. It's not just variable lifetime
what the C++ compiler tracks. But you're right, something like FILE*
=fopen, very similar to lua io, is RAII too. The problem is I normally
want proper value lifetime tracking, which is hard to do without