Author: Roger Leigh Date: To: dng Subject: Re: [DNG] GTK (was Will there be a MirDevuan "WTF"?)
On 24/07/2015 23:58, T.J. Duchene wrote: >
>
> On 7/24/2015 3:57 AM, Roger Leigh wrote:
>
> First, thank you for the reply, Roger. I supremely appreciate it.
>
>> The C++ compiler objectively does a better job here. It's simpler,
>> quicker to write, safer, easier to refactor. And when I've done a
>> full conversion of GObject-based C code to C++, the C++ compiler has
>> picked up on real bugs which the C compiler hadn't picked up on
>> (because the type information had been deliberately cast away). GTK+
>> programs can be riddled with bugs, without the developer being any the
>> wiser in the absence of compiler diagnostics.
>>
> That is true to some degree. I don't agree entirely. It really depends
> on the compiler and what settings are being used. GCC is not the
> world's greatest compiler by any stretch of the imagination, and there
> are a lot of extraordinarily lazy FOSS programmers who ignore warnings,
> and do not initialize variables before using them.
It's worse than this, and is nothing to do with the compiler and
everything to do with unsafe practices in the libraries. With
GTK/GObject, suppose I use one of the macro casts for polymorphism such
as GTK_WIDGET(). This cast casts a pointer to a (GtkWidget*) with a
little checking. But it's essentially just the same as (GtkWidget*).
This "works" if you use the correct cast macro with a variable of the
correct type. BUT. What if you get it wrong? You have explicitly cast
away the real type and told the compiler to use a completely different
type. There is *no way* the compiler can issue a diagnostic if you got
it wrong. In C++ this simply doesn't happen; upcasting is completely
transparent, downcasting with dynamic_cast is completely safe. This can
lead to long standing latent bugs in the codebase that are well hidden.
That's the start. Now consider stuff like signals and closures,
g_signal_connect, g_cclosure_invoke etc. What happens to type-safety
here? Again, it's almost always completely lost. What happens if you
screw up? Nothing. You would get no diagnostic from the compiler, and
this would result in bad things at runtime. In C++ with libsigc++,
Boost.Signals etc. the signals and handlers are templated and specific
for the signal and handler types, even going so far as to be able to
rebind and elide arguments. If you get it wrong it will fail to
compile, not crash and burn at runtime. And with the gpointer (void)
data pointer in the signal, used to pass arbitrary data or object to the
handler, that's completely unsafe--the handler has no guarantee it's
going to get what it expected. Again, the C++ handlers don't do
that--it's completely safe and checked at compile time.
This is not about "programmer laziness"--they were not in a position to
be notified of any mistakes they made, at all.
> No one can blame you
> for disliking the fact that GTK tends to leak references (at least from
> warnings I seen on the console) when using Linux. That's entirely out
> of your hands.
No. It means the programmer screwed up the reference counting. *Every*
instance is programmer error. Since different object types handle
reference counting differently and inconsistently, this is a very
difficult thing to get right. Do you get a newly-created object with a
refcounf of 1? With a floating reference? Do you need to sink it?
It's a nightmare. This is one reason the GTKmm bindings are nicer--they
handle it correctly for you and give you a consistent and transparent
way to handle it (GLib::RefPtr). No more manual refcounting, and no
inconsistency makes it impossible to screw up.
> If I had to critique GTK based on what little you have
> told me, I'd say it was probably a bad design, trying to force OOP in C.
It's definitely both of these things. C is entirely unsuited to OOP if
you care about the result being correct and robust.
> That is not to say that OOP cannot be done in C, but as a programming
> paradigm, I personally feel that OOP is a very flawed idea. I've been
> programming for a long time, and to be perfectly honest, I have seen
> very few cases where OOP methodology actually makes things "better".
> There are some nice features, but I don't buy the whole idea as actually
> making software development easier. I'd sacrifice most of those features
> in a heartbeat not to have to deal with exceptions.
I think this is at odds with general consensus to be honest. OOP can
certainly be overused where other approaches would be more appropriate,
but in the general case it provides many concrete benefits, so long as
you don't try to do polymorphism in C.
>> This too also has its limits, but put it this way: I haven't had a
>> memory leak in C++ code in a decade due to the use of shared_ptr, and
>> this isn't something I can say for my GTK+ C code, or GTK+ C code in
>> general.
>
> I would qualify that statement by saying you have not had a leak as
> long as an exception was not generated.
Absolutely not. All the code is completely exception safe and will not
leak if exceptions are thrown. That's what RAII and smartpointers take
care of. Running under valgrind shows zero leaks with exceptions being
thrown all over the place. Exception handling can be *completely
robust* when you use modern C++ techniques.