Ok so can i start converting libs to C++ WITHOUT exception fencing then?
Change the file suffix, compile them with C++,  resolve the noise, and
maintain the C  linkage for the those that exist. Then as developers want
to start using C++ constructs they can install any appropriate exception
handling and cleanups.
Is that a desirable step to make in your opinion?



On Fri, Feb 6, 2026, 10:20 AM John Ralls <[email protected]> wrote:

> C++ isn’t a new undertaking for GnuCash. Chris, Geert, and I have been
> working on it for over 10 years and Christian Stimming had a working Qt
> experimental GUI (since archived) 15 years ago. Libgnucash is already more
> than 2/3 compiled with C++ (191 .cpp vs 89 .c) and gnucash (where the GUI
> code lives) is more than 20% C++. While much of that is just changing the
> file type and cleaning up the compiler errors, other parts—GncNumeric,
> GncDateTime, GncOptions, Quotes, the DBI/SQL backend, and the CSV
> importer—have been completely rewritten into real C++, plus quite a few
> Glib containers converted to STL ones.
>
> Regards,
> John Ralls
>
> On Feb 6, 2026, at 06:44, Stefan Koch <[email protected]> wrote:
>
>
> One more thing to keep in mind for the c to c++ conversion...  The c++
> compiler is stricter on some type checking.  You will have to make real
> code changes to allow it to compile some c code.  Those changes are not
> significant, but do have to be correct and verified.  At least that is what
> happened when I did this for some test driver source files.
>
> Stefan
>
> On Fri, Feb 6, 2026 at 9:28 AM <[email protected]> wrote:
>
>> John, thank you for your detailed reply.
>> I've responded inline below
>> If you are still unconvinced please say so and I'll abandon this.
>> Thanks again.
>> - russ
>>
>> > -----Original Message-----
>> > From: John Ralls <[email protected]>
>> > Sent: Thursday, February 5, 2026 9:04 PM
>> > To: [email protected]
>> > Cc: [email protected]
>> > Subject: Re: exception fencing
>> >
>> >
>> >
>> > > On Feb 5, 2026, at 3:03 PM, <[email protected]>
>> > <[email protected]> wrote:
>> > >
>> > > Since this is my first attempt to submit code to the GNC project I
>> > > thought I’d pass my approach through the established developers first.
>> > > I am interested in converting GNC code from C to C++ which will occur
>> over
>> > time so that the review quanta is not too overwhelming.
>> > > I plan to convert build targets to only use the C++ compiler over
>> time.
>> > > Anything that is exposed with C linkage I plan to carry forward
>> expecting at
>> > some point all the callers will be C++ as well and most if not all of
>> the C-
>> > linkage requirements will go away.
>> > > Any C++ code that is called from C-code will need a mechanism to
>> prevent
>> > C++ exceptions from bleeding back.
>> > > I’ve developed a header file except-fence.hpp that provides the
>> required
>> > fencing.
>> > > My first patch will be just this header file and the associated test
>> files, so no
>> > GNC code will be affected initially.
>> > > I wanted to make the footprint small since I expect the fences will
>> eventually
>> > be removed.
>> > > My approach is to replace the definition if the C-API functions with a
>> > > macro that defines a stub C-API (extern “C”) Which instantiates an
>> > ExceptFence object and uses the “forward_to” method call a local static
>> > function with the original body.
>> > >  For Example:
>> > >  const char *
>> > > func1(int a, gpointer b) // defined as extern “C” in header file { … }
>> > >  Becomes:
>> > >  SAFE_C_API_ARGS(const char *, func1, (int a, gpointer b), (a, b)) { …
>> > > }  Which (essentially) expands to:
>> > >  static const char *loc_func1(int a, gpointer b); extern “C” const
>> > > char *func1(int a, gpointer b) {
>> > >     ExceptFence exf;
>> > >     return exf.forward_to(loc_func1, a, b); } static const char
>> > > *loc_func1 (int a, gpointer b) { … }
>> > >   The essence of forward_to is the following:
>> > >         template<typename Func, typename... Args>
>> > >         auto forward_to(Func&& func, Args&&... args)
>> > >         {
>> > >             try {
>> > >                 m_except_data.exception_hit = true;
>> > >                 auto result = func(std::forward<Args>(args)...);
>> > >                 m_except_data.exception_hit = false;
>> > >                 return result;
>> > >             }
>> > >             catch (const std::exception& ex) {
>> > >                 m_except_data.exception_type = &typeid(ex);
>> > >                 m_except_data.exception_message = ex.what();
>> > >             }
>> > >             using ReturnType = std::invoke_result_t<Func, Args...>;
>> > >             if constexpr (std::is_integral_v<ReturnType>) {
>> > >                 return
>> static_cast<ReturnType>(m_exception_error_integer);
>> > >             } else if constexpr (std::is_pointer_v<ReturnType>) {
>> > >                 return static_cast<ReturnType>(nullptr);
>> > >             } else {
>> > >                 return ReturnType{};
>> > >             }
>> > >         }
>> > >  This definition of forward_to() supports functions that return
>> integer types,
>> > pointer types, and structure types.
>> > > That appears to support most of what we need that I’ve seen.
>> > > There are 4 different SAFE_C_API macros to support all the
>> combinations of
>> > void args and void return types.
>> > >  Anyway, if there are concerns about this approach, or request for
>> more
>> > details please let me know.
>> > >  Thanks for your attention and support.
>> >
>> > Getting rid of C entirely requires changing the GUI framework; the
>> minimum
>> > effort would be gtkmm but even that will be a lot of work. It isn’t
>> going to
>> > happen any time soon.
>>
>> [russ] I figured there might be some elements that are impractical to
>> convert
>> But I still think it makes sense to enable C++ coding in the main. There
>> are just a lot
>> A nice features of C++ that would be good to take advantage of.
>>
>> > Also to consider is that exceptions either can’t be
>> > allowed to leak through the Python and Scheme bindings or those bindings
>> > need to acquire exception converters.
>>
>> [russ] Yeah I thought that the binding interfaces would need to remain as
>> C-Linkage but can still be C++ code underneath.
>>
>> >
>> > Just switching to compiling C code with a C++ compiler doesn’t introduce
>> > exceptions so the need to wrap calls in try/catch is limited to cases
>> when the
>> > function is reimplemented to use some C++ thing that throws.
>>
>> [russ] right but the code will be available for use  of C++ constructs by
>> developers but still callable from C compilation units
>>
>> > Note that
>> > loc_func1 still has to check ext.m_except_data.exception_hit and if
>> it’s true do
>> > something with the rest. I suspect that that something will turn out to
>> be
>> > sufficiently not generic that having the template won’t really save
>> much over
>> > just catching the exception in the implementation function or writing a
>> C
>> > wrapper that handles exceptions in a way that’s appropriate for the
>> execution
>> > context at hand.
>>
>> [russ] I'm not sure I agree completely. The fence is only for catching
>> unhandled exceptions (coding bugs), and the fence is in func1(), but the
>> implementation logic is in loc_func1(). Even carefully designed C++ can
>> have unusual circumstance that result in an unexpected exception. If there
>> is any cleanup that needs to be done (beyond returning some error value),
>> that will need to be done with a try/catch in loc_func1(). For functions
>> that generate a lot of side effects and have complicated unwind logic its
>> likely they won't be able to do that with a giant catch-all at the top
>> anyway and need layers of try/catch to properly deal with them. I agree
>> that if we mandate a giant catch-all at the top of all the C-APIs when
>> implementing that might work for catching everything but in my experience
>> its tricky to get right and error prone. E.g. if we instantiate an object
>> before the try, those constructors can throw unprotected.
>>
>> >
>> > BTW, “m_exception_error_integer” is a problem because it implies that
>> that’s
>> > a single value used for all cases and it’s not hard at all to think of
>> cases where
>> > different values would be needed for signaling an error.
>>
>> [russ] in the implementation of ExceptFence, the constructor can take any
>> integer value and use that as the error value for integer return types. But
>> you are right that the macros don't currently support that, but that would
>> be easy to change. From what I've seen so far the return types for these
>> APIs in the code base are either some kind of integer, some kind of
>> pointer, or some kind of structure. The class currently supports specifying
>> what the integer error value is for uncaught exceptions, but for the other
>> return types it currently only supports nullptr/zeroed-out-structure, but
>> that also could be fixed to support any error value of those types.
>>
>> So the exception fence really just ensures that uncaught exceptions
>> return a known error type and that the implementation function does not
>> need a v. carefully designed giant catch-all at the top.
>>
>> Void functions are tougher. Caught exceptions currently just return and
>> leave an unknown state behind without any side effects. If there was some
>> notification possible that would be nice.
>>
>> Once nice thing of having the fencing in a single class is if you suspect
>> an unhandled exception e.g. in a void C-API func, it’s a single breakpoint
>> in the code.
>>
>>
>>
>> >
>> > Regards,
>> > John Ralls
>>
>>
>> _______________________________________________
>> gnucash-devel mailing list
>> [email protected]
>> https://lists.gnucash.org/mailman/listinfo/gnucash-devel
>>
>
>
_______________________________________________
gnucash-devel mailing list
[email protected]
https://lists.gnucash.org/mailman/listinfo/gnucash-devel

Reply via email to