[GRASS-dev] grass is a monad?

Glynn Clements glynn at gclements.plus.com
Fri Jan 15 18:46:48 EST 2010


Maris Nartiss wrote:

> Some rumbling form bad code author.
> Still I don't see why GRASS modules would not benefit from ability to
> clean up after themselves in case of failure. Removing temporary maps,
> closing open DB connections etc. are good reasons why GRASS modules
> should do error checking by themselves, unless it IS a FATAL error
> (one that means serious module code error or something terribly wrong
> with data files/software/hardware when any future action might result
> in even larger disaster).

Most clean-up is done automatically by the OS when the process
terminates. The main exception is that files won't be deleted. For
files which are part of the GRASS database, the libraries should
handle this.

Modules can use G_set_error_routine() to install a fatal error handler
if they want to perform clean-up. This is why that function exists
(i.e. to perform clean-up prior to termination, *not* for trying to
prevent termination).

If this isn't sufficient, please suggest improvements.

> IMHO decisions when and how to push the Big Red button should be left
> to module authors. Library functions returning i.e. -1 is not so big
> issue to check in module code and then call lethal error there
> (possibly after rm'ing temporary files etc.).

That puts a lot of work onto module and library authors.

When I recently changed Rast_open_* and several other core functions
to generate fatal errors rather than reporting an error indication, I
changed everything which called them to not check for an error
indication (which cannot occur now). A significant number of modules
didn't actually check for any error indication, so if the call failed,
they would go on to try to read/write data from an invalid map or use
the contents of a "struct Cell_head" which wasn't actually
initialised.

Returning a status also means that each library function must check
the status and report it back to the caller, all the way up to the top
level. The caller then only knows that an error occured; it doesn't
know where it occured or exactly what occurred, so it cannot report
the details to the caller.

Historically, C has used this mechanism due to the absence of any
alternative. The main downside is that error handling can often
account for the majority of the code, particularly if you end up
having to write:

	a = foo();
	if (a < 0)
		 error(...);
	b = bar();
	if (b < 0)
		error(...);
	x = a + b;

rather than just:

	x = foo() + bar();

Modern languages invariably have an exception mechanism which allows
an exception to be raised in a low-level function and caught at the
higer levels without burdening all of the intermediate levels with the
details, while allowing the top level to find out the precise nature
of the error.

If it wasn't for the fact that C++ code takes roughly five times as
long to compile as C, I'd advocate converting GRASS to C++ solely so
that we can use exceptions and RAII (I don't see any need for OO, and
if there was, it's easy enough to implement in C).

It's possible to implement exception mechanisms in C using setjmp()
and longjmp(). However, the syntax is inevitably ugly, you have to
manually restore the exception handling on early returns, and you
can't use destructors for clean-up.

-- 
Glynn Clements <glynn at gclements.plus.com>


More information about the grass-dev mailing list