> It needs to use basic data structures, so it uses GLib. It also need to support runtime-defined connection graph, so it is built on top of GObject.
That's running into the age old trap of trying to shoehorn an OOP system into C, just don't do that ;) E.g. don't design your systems around the OOP paradigm in the first place.
If at least C solutions took advantage of abstract data types as advocated by modular design approaches before OOP took off, but no it is all reaching out to field data directly with macros, and clever pointer tricks that fail down.
There are several books on the matter, that obviously very few read.
Here one paper example from 1985 on the subject, "Modular programming in C: an approach and an example"
https://dl.acm.org/doi/10.1145/382284.382285
> If at least C solutions took advantage of abstract data types as advocated by modular design approaches
People have been writing C code with ADTs and "Modules" from the very beginning.
Two excellent examples which come to mind are; Andrew Tanenbaum's Minix book Operating Systems Design and Implementation and David Hanson's C Interfaces and Implementations: Techniques for Creating Reusable Software.
And of course the Linux Kernel is full of great modular C techniques which one can study.
Unfortunely I have seen plenty of counter examples since 1991.
Starting with RatC from "Book on C", 1988 edition, over to Turbo C 2.0 in 1991, all the way to modern times.
That is just not how most C codebases look like.
Nope, you are just generalizing your opinion which is not quite true. My (and my colleagues) experience studying/programming C/C++ from the beginning-90's has been pretty good.
When the PC explosion happened, a lot of programmers without any CS background started with C programming and hence of course there is a lot of code (usually not long lasting) which do not adhere to software engineering principles. But quite a lot more C code was written in a pretty good style which was what one picked up at work if not already exposed to them during studies.
I still remember the books from late-80's/early-90's on the PC side, by authors like Al Stevens (utils/guis/apps using Turbo C) who wrote for Dr. Dobb's Journal. On the Unix side, of course you had Richard Stevens, P.J.Plauger, Thomas Plum etc. They all taught good C programming principles which are still relevant and practiced today.
Each one is their own anecdote.
I have also all those books and magazines, pitty most coders of the code I have seen on my lifetime don't.
The regular developers, those that don't give a shit online forums exist, other than Stack Overflow, and go home to do non computer related stuff after work.
As i said, you cannot generalize from your experiences alone.
You have to look at the programming community as a whole and industry practices developed and adopted over time in the real world.
There is enough data here to show that C does not deserve the negativity that i often see here on HN.
You know what gstreamer does, right? It's a dynamic multimedia framework - you give it pipeline defined by string, like:
ximagesrc display_name=:1 ! video/x-raw,framerate=20/1 ! videoscale ! videoconvert ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast ! rtph264pay ! udpsink host=127.0.0.1 port=5000
and it automatically loads .so files, creates all those components and connects them to each other. Super handy for all sorts of fun audio/video processing.
So all that C ceremony is required because user _should_ be able to say "ximagesrc display_name=:1", and possibly dynamically change this attribute to something else via script command (because a lot of time gstreamer is embedded in other apps).
So if you know how to achieve the same without trying to "shoehorn an OOP system into C", do let me know. But I bet whatever solution you came up with would be very close to what GStreamer ended up doing, if not even more complex.
(Unless what you are trying to say is: "If problem's most-efficient representation is OOP-like, don't use it with C because C is for simpler problems only. Use complex languages for complex tasks." If that's the case, I fully agree)
> and it automatically loads .so files, creates all those components and connects them to each other. Super handy for all sorts of fun audio/video processing.
I created a quite similar OOP system for C around 1995 (as I guess did most programmers at that time who were fascinated by Objective-C), classes were implemented in DLLs and were loaded on demand, classes were objects themselves, the tree of class objects could be inspected (e.g. runtime-type-information and -reflection), and the whole system was serializable - this was for a PC game (https://en.wikipedia.org/wiki/Urban_Assault).
It looked like a neat thing at the time, but nothing a couple of structs with function pointers or a switch-case message dispatcher wouldn't be able to do just as well, definitely not something that should be the base for more than one product, and most definitely nothing that should have survived the OOP hype of the 90's ;)
This kind of automatic property serialization/deserialization, however, has traditionally been a sore spot for C++ as well.
You can do it, but you will have to either repeat yourself at least a little, use some very ugly macros, or use a code generator.
And many of those ugly macro tricks work in C as well. So do code generators.
That said, as C++ has added features, this type of metaprogramming has gotten easier and easier, and more and more distinct from C. This culminates in C++26 reflection which will finally make it possible to just define a struct and then automatically generate serialization/deserialization for it, without hacks. Once reflection is implemented and widely adopted, then I will agree with you that this should be 1 or 2 lines in a well-structured C++ app.
Unfortunately your insightful comment is 30 years too late. You'll have to find a time-machine and go back to the 1990s and tell GNU/GTK/Gnome/etc that they are doing it wrong.
Good luck making any sort of UI without OOP-like methods. The moment you have grouped state (say "button_enabled", "button_shown", and "button_checked") and corresponding methods, you get something OOP-like.
The only way to work around is immediate mode UI, but this requires fairly powerful CPU, so it's only feasible on the modern machines. Certainly not something that people would want about 30 years ago, they still cared about performance back then.
Immediate mode UI doesn't require a powerful CPU and was invented in 2002, so about 24 years ago. I think the belief that it necessarily sacrifices performance is somewhat of a misconception.
Compare a hypothetical "Immediate Mode" counter:
To the equivalent "Retained" counter: The only difference I see here is whether the stateful "cache" of UI components (ctx->textbox and ctx->button) is library-side or application-side.You are looking at it from the user side, while all the interesting parts are on the implementation side:
- If you have partial redraw request, can you quickly locate _only_ the controls which are covered and only redraw those?
- If you are clicking on something, can you quickly locate which component will receive the click?
- If you are moving mouse, or dragging a selection, can you quickly determine if any components should change the state? Can you avoid running the full event loop on every mouse move event?
- If your application state has updated, do you need to force redraw or not? (Many immediate mode UIs fail badly here, never going to idle even if nothing is happening)
This is all trivial in the old-style UI - efficient redraw / mouse mapping is table stakes in the older GUIs. While all that immediate mode can do is to keep running redraw loop _every_ _single_ _time_ something as trivial as mouse move is happening, just in case this can change highlighted item or something.
(Unless the "immediate mode UI" is just a thin veneer, and library is using good-old OOP based GUI components under the hood... but in this case, it's still faster to cut out the middleman and control components yourself)
And yes, back when I was doing "game development" class in college, around that time, I've used the immediate mode UI for menus. This only makes sense - games run on foreground _anyway_, and they basically consume 100% of CPU anyway. But for regular apps? Please don't.
Example: I just opened https://www.egui.rs/#demo in background tab... The browser's task manager shows this tab never goes idle, consuming between 0.1% and 3%. Considering I often have 40+ tabs open, this can take a significant part of CPU.
Immediate mode GUIs, unless in app which already uses 100% CPU, like game or video player, will always be less efficient than classical event-driven ones.
You appear to be making assumptions about immediate mode UI limitations based on some implementations you've worked with and not based on what's actually dictated by the interface itself. You touch on this somewhat by claiming that it's possible to be fast as long as the UI is merely a "thin veneer" over something more stateful, but that isn't a distinction I care about.
I'm not a good advocate for IMGUI; there are resources available online which explain it better than I can. I'm just trying to point out that the claim that immediate mode GUIs are some sort of CPU hog isn't really true. That's what I meant by "doesn't necessarily sacrifice performance," not that there is literally zero overhead (although I wouldn't be surprised if that were the case!).
> ...The browser's task manager shows this tab never goes idle...
As far as I can tell, the demo you linked appears to be bugged. You can see from poking around in a profiler (and from the frame timer under the "backend" popout) that the UI code does in fact go idle, but the requestAnimationFrame loop is never disabled for some reason. Regardless, even if this particular GUI library has problems going idle, that's not an inherent problem with the paradigm. I get the impression you understand this already, so I'm not sure why you've brought it up.
> Many immediate mode UIs fail badly here, never going to idle even if nothing is happening
ImGui's author deliberately doesn't fix this because this is one of the main issues preventing ImGui to be widely adopted on desktop potentially attracting too many users at once but lacking support for all of them.
https://github.com/ocornut/imgui/issues/7892#issuecomment-22...