Subject Re: [Firebird-Architect] XSQLDA/XSQLVAR issues
Author Jim Starkey
Samofatov, Nickolay wrote:

>>If we build in a function to register a callback
>>with a known calling sequence, we can the callback in your
>>call to throw the actual exception. The API implementation
>>code doesn't care about the mechanisms of the exception, just
>>that a responsible adult does whatever is required to make
>>sure that it never returns from the exception callback.
>>
>>
>
>Sorry for repeating myself, but I already explained earlier that this
>approach is not nice and told about portable alternatives.
>Exception handling is not magical thing and compiler needs to know a lot
>to throw, pass and catch exception properly.
>
>
>
I'm sorry, but you seem to have missed the point. The API doesn't throw
an exception, it passes a pseudo-object to a registered callback.

Let's review how we got here:

1. The API should be functional, specifically meaning that only one
things is returned. This precludes passing structures by
reference, globals, or thread globals.
2. The API should be object oriented, but defined as POD (plain old
data) structures that just happen to map to C++ objects on certain
platforms. The objects should be opaque, meaning data is
accessible only through methods. The advantage of objects is that
they are extensible and polymorphic.
3. Exceptions are always errors. Expected results do not throw
exceptions.

Rule #1 precludes a status vector. Rule #2 precludes any static
structure. Rule #3 suggests that a non-standard return is appropriate
for exceptions.

There is no disagreement that exceptions can't be thrown across
compilation boundaries. A call back, however, doesn't suffer from this
problem, and has the added advantage of making the object lifetime of
the exception object clear -- the duration of the callback.

>One of the portable ways to pass exception pseudo-object is to store it
>in dynamic thread-specific exception buffer.
>Sample Windows implementation of this approach may be found in
>BV_Stable3 branch of Firebird tree (see platform.cpp file), it is used
>there to implement exception passing across Trace API boundaries.
>POSIX implementation is very similar.
>
>
The use of globals has always been bad practice. The use of thread
globals is just as bad, maybe worse, since we now know better. Thread
specific data is useful to find an object that describes the thread
itself. I'm prepared to argue that any other use is poor design. The
Firebird thread data is a poster child of poor design. Before
exceptions were introduced, it did provide the address of a status
vector to put exception data before doing an longjmp error return. With
the introduction of exceptions, it should have been removed. Instead,
it has become a crutch to pass informal parameters like database and
attachment pointers to functions that weren't otherwise supplied with
these. This is bad practice and we should remove all examples from the
codebase.

One of the fine properties of Cutler's VAX/Eln operating system was that
code had to be pure -- no globals whatsover were allowed. It was good
practice. To back this up, the Bliss compiler had a very nice feature
where a linkage could be declared in which a specific parameter was
passed in a register. In Rdb/ELN this mean that a pointer to the
attachment block (if I remember correctly) was parked in a register and
passed -- still in the register -- to all functions, establishing
context. Globals were unnecessary, and after a surprising short period
of time, we unmissed.

--

Jim Starkey
Netfrastructure, Inc.
978 526-1376