lua-users home
lua-l archive

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


David:

On Fri, Jun 21, 2019 at 9:12 PM David Heiko Kolf <david@dkolf.de> wrote:
>
> I have now done some further research in other languages, too.
> C# as I already wrote returns the last error.
> JavaScript also returns the last error:
> <https://www.ecma-international.org/ecma-262/6.0/#sec-try-statement>
> Java as you wrote returns the first error and logs all further errors:
> <https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html#suppressed-exceptions>

I'm nearly sure you are mixing concepts here, comparing try/finally in
C#/JavaScript with try-with-resources. They are different animals.
Java has try-finally too and it probably works similarly to its
equivalent in C#/JS ( I say probably because I don't do windows, hence
no C#, and I'm not too familiar with JS, I just know how Java works ).

I do not recall Java logging supressed exceptions ( AAMOF I would
consider this a serious fault in a serious language for serious works,
and your docs point to it just recording them and letting the
programmer handle it, which is IMHO much more correct ). Maybe if the
exception terminates the programthe outer layer prints it and logs it
fully along with any supressed component, I'm not sure as it has never
happened to me, I may try to force it )

Lua <toclose> is not like try/finally, it's like the
try-with-resources variant, which, IIRC, is the WITH in python. And
very similar to destructors in the RAII supporting languages (
CPython/Perl, which are ref-counted, or C++ and cousins ).

> This would be similar to the warn function, as "nobody" already
> suggested in this thread earlier. (I just hope that the warn message
> handler gets more flexible than it is at the moment).

I hope they do not send them there. Storing it like Java, having a
getsupressederrors() method, smething like it, may be fine, but I do
not want error descriptions forcefully polluting my warn stream ( of
course I could use an outer <toclose> to divert it, but it's not a
pretty thing ).

> C++ terminates the application once a second error happens:
> <https://stackoverflow.com/questions/130117/throwing-exceptions-out-of-a-destructor>

mmm, it's a little more complex, but basically corect, you cannot
terminate exception handling code via an exception ( You can use
exceptions, but must handle them ),and you should not let exception
leak from destructors unless declared, and it's tricky ( but using a
try { close_which_may_throw() } catch .... is kosher ) ( And the
rationale is expected, destructors run at a point where the object is
going to be destroyed, trying to allow recovery there will just
propagate around all the language and solve nothing, you need
invariants like that. If you throw and "out of space" error on a file
close ( one of the things people usually forget when using things like
STDIO, fclose() is one of the functions which may fail ), there is
little you can do to recover from it ( the file is indeterminate )).
It's very usual to find file-like classes with explciit close() which
can throw and/or  report errors which are used in the destructors with
a default handling ( of catching, logging and/or ignoring and
foloowing on ).

> Lua in xpcall returns "error in error handling":
>   xpcall(function () error "1" end, function () error "2" end)
> (Yes, that is not an exact match to __close, but still a similar case to
> me).

It should not be, IMO. That is a very specific way of doing it, more
restricted even than try/finally emulation via pcall. The message
throwing is a big sin, IMO, and it cannot be used for resource closing
as it is not even called on error.A difficult to understand error
message there seems Ok, you error in the middle of stack unwinding,
choice are very limited. It is similar to how many CPUs completely
halted on triple-faults.


> Francisco Olarte wrote:
> > IMO __close methods belong to resource/service objects, and it's no
> > throw behaviour can normally be unit tested on them, giving a way to
> > easily catch errors in them will lead to more difficult code in the
> > well written cases and, what is worst, send a message theat "throwing
> > in __close" is ok, and instigate people to write __close without care.
> I agree that __close should be written very carefully but I am not sure
> that ignoring errors will lead to extra careful code in general. So from
> the point of view of education the C++ approach might be the best...not
> sure I'd like to see that in Lua.

ALL code should be written carefully, unless explicitly noted ( like
when I post a couple of examples and say "sample code-do not rely on
it". But my point is the development process is different. <toclose>
is great for LIBRARY objects, like the builtin files, or a socket
library, which is (unit) tested, because IT CAN before incorporating
it in your application, and where you can rely on __close not
erroring. You rely on __close() not throwing as you rely on 1+1 being
2 or on socket.write sending data to the network.
For complex error handling you use try-finally or similar stuffs. Try
finally can be done but not with a patter like your xpcall sample, but
with two pcalls. You pcall the try-code and store the result ( error
or ok). Then pcall the finally code, and store it. Then you have four
outcome. When finally is ok it's easy, you error or return depending
on try result. But when finally fails you are in a weird place, and
can do many things. I normally copy the behaviour of one language I
know, say Java, because lot of smart people have spent lot of hours
thinking on it and normally I found they had godd reasons for that (
afterusing my copy of it a bit ).

The C++ approach is totally different. C++, like perl, has all the
objects scoped and with a very precise definition.The beauty of it is
you can implement nearly everything building on it. No finally? a
three lines class gives you a finally construct which you can activate
wherever you write it. No to close? write it, it's not pretty, but
it's easy. No (pythonic) with? write it. I've found that my C++ code,
once it compiles and links, is debugged pretty fast due to te strict
definition of lot of things, but it is not easy.


> > That's true, but IMO a construct like that ( oportunistic closeing
> > code written in the same code chunk as the mian one ) would be better
> > served by one of the many ways you can simulate a try/finally.
> That code was just supposed to be a short example that is easy to run in
> an interpreter, the created object should resemble a real object with
> resources. (In another answer in this thread I have now written a more
> realistic version).

Well, you totally made me think otherwise, as the code you wrote (
closing code, no access to stored state ), seemed like you totally
wanted to make an example of a double fault due to an error on a
finally clause. An "easy" way of simulating "try T finally F" in lua
would be something like (UNTESTED)
-- library
function _FINALLY_CLOSER(self) self.f(unpack(self.args)) end
_FINALLY_META = { __close = _FINALLY_CLOSER }
function FINALLY(f,...) return setmetatable(_FINALLY_META, { f=f, args={...} })
-- usage
do
  local x <toclose> = FINALLY(F)
  T()
end

Francisco Olarte.