[VOTE] Could you use LVGL if it were based on C++?

LVGL is supposing designed using C object orientation but from usability perspective, it’s far from a proper C++ API. For example, something I facing now while migrating to LVGL 8.x, I have a LVGL Label object and I want to find all the operations I can do on it. With C++ it would trivial using the IntelliSense code completion, but with the current LVGL API, it’s a long search in documentation and reverse engineering the code that is based on knowing relation between name prefixes (lv_obj applies also to lv_label) and on mysterious ‘parts’ enums that may or may not be related to the Label object. A search that often lead nothing.

A native C++ API will be a major step forward IMO, adopting more modern, productive, and maintainable coding practices.

Normally it should be all lv_obj_... and lv_label_... functions. Exactly what caused the headache?

With proper C++, to find the label operations I could type my_lable. and IntelliSense will resolve the inheritance and will show all the applicable methods. With the current LVGL, I need to know all the parent classes, their prefixes, and try each one of them with IntelliSense to see what comes up.

Same goes for contained objects, let’s say I type my_label. and see series(int), I continue with my_label.series(0). and intellisense will show me what is relevant for the server.

I think it reasonable to conclude that a more modern C++ API will be more user friendly and more productive. :wink: An I am not talking fancy things such as STL, and containers, just basic proper object oriented structures that modern tools and IDEs can understand.

I see. Have you seen this discussion on GitHub?

I was nor aware of it. Thanks.

I’ve ported many code from C to C++ in the last 10 years. From my experience, the C++ version is usually smaller, safer and faster. The C++ compiler is doing crazy optimizations that aren’t possible with C because of type erasing (the fact that the type becomes a void * breaks all future optimizations based on type deduction).

I’d like to correct few things in the discussion above:

  1. virtual table are not per instance, but per class (they are “static” pointer arrays in C++ terms). Since LVGL is doing its own pseudo virtual table based on string comparison to locate the right type, it’ll be more efficient to use C++ here
  2. C++ would allow removing the lv_ type prefix for each type, many, if not most of the get/set parameter. It’s a lot less method to remember / search for in the documentation.
  3. Making a C++ API on top of the C API is a bad idea, IMHO, since it’ll just bloat the binary. If the compiler breaks on void * in every method it enters, it’ll fail to inline, reuse, optimize as much as possible. That’s a bad news for “an easy” port, because it’ll just provide frustration (your port requires double work since you must duplicate all the C API and you get no gains). The right move, for me is to rewrite in C++ and rework a C api on top of the C++ code.
  4. Template, when used smartly (that is, not to make a hell of any maintainer, user) are very useful to help the compiler deduce the semantic of the code. If you look at this project I was able to construct a full MQTT v5 client in only 80kB of binary space (and 50kB on ESP32). For those you know about MQTT, it’s a protocol with variant type, many messages and properties. The best C solution are building at ~250kB and are slower by at least 2x.
    In that code, I used templates to generate all the common code for all different properties types (in LVGL, it would be all the common stuff of widgets) and a virtual inheritance just for the actual difference (with the goal of minimizing the binary space). The compiler is able to infer all the common part and remove virtual table for most classes so you don’t even pay a runtime cost for when the type used is only the child type. Also, it makes code size small and manageable (the entire client is ~5000 line of commented code). See here for the explanation of how this was done.
  5. The claimed “overload” of C++ standard library is wrong. Unless you actually need 1998’s stuff (like iostream and other initial dumbness), C++ standard library is most likely optimized away. I’m not using any STL stuff nor any RTTI in my ports so you don’t pay for what you don’t use.
  6. Type safety is one of the subtle place where C++ shines and where a C developer take a slap in the face with the lengthy compiler error message compared to the basic and wrong solution of casting everything to (void *). There is no solution to this but to learn to read those message and understand them. Sorry.
  7. Compile-time computation of many stuff is also a place where C++ shines. Every time you see a chain of strcmp(abc, "some text") in C, you’re killing a unicorn. In C++, compile-time string hashing is a reality so the O(N*M) algorithm above magically becomes a O(1) or O(N) algorithm. This also means a smaller binary since the some text string does not have to be stored in the binary anymore, only its hash value. Same goes for hash table, maps, and printf like stuff. You can even precompute CRC tables, ternary tree or even a C compiler that compile string-based C code at compile time.
  8. Debugging of C++ is a bit harder than C. But debugging LVGL is already a nightmare with all the type erasing (void *) everywhere, so in that specific case, I think it’ll be the same difficulty.
  9. Stack space requirement of C++ code is usually larger (since well written embedded C++ code does not use the heap that much or at all). That might or might not be an issue.
  10. Parsing C++ code by IDE used to be a lot worse than C. Now, with intellisence and clangd, it’s considered done. In the case of LVGL, it’ll be a lot better since, again, type erasure prevents code analyzer to deduce the actual interface of the objects. In C++ you’ll get all the class hierarchy in your IDE and not in the documentation.
  11. Generating binding with other languages will be harder in C++ than in C. C is the de facto lingua franca
  12. C++ is not harder to learn than C. You can limit yourself to only a small subset of C++. Class, basic template, namespaces, variant, and you will likely master all that’s required to build a performant code. No need to learn or understand the cryptic answer from C++ guru on stackoverflow, if you need those answers, your code is likely wrong anyway since it won’t be maintainable.
5 Likes

Thanks for this great summary. It was very informative.

I see the advantages of a C++ base with a C wrapper, but as the poll shows half of the users (at least who answered) need C. :frowning:
image

X-Ryl, You are right on every point, I agree with everything you said. I have only one thing to add. It’s not too difficult to build a good C binding to a C++ API (and with very little overhead), whereas (your point 3) the opposite is not true.

1 Like

In terms of the poll I am for LVGL remaining written in C for language binding reasons (aka the, I can use only C poll answer). Currently I am developing a series of Kotlin libraries that provide Kotlin bindings to LVGL/LV Drivers that are known as LVGL KT. Despite all of its faults the C language does have some advantages. Some of the advantages that are beneficial to language bindings are the following:

  1. Binary and source backwards compatibility (C++ has a poor backwards compatibility track record)
  2. Only a single variant of the C language (unlike C++ which is fragmented into many variants), which helps ensure backwards compatibility
  3. Easily portable to different platforms
  4. A huge number of platforms are supported
  5. Many high level languages support interop with C like Python, and Kotlin for example
  6. Lack of OO (Object Orientation) support makes it easier to develop some language bindings; especially for languages that don’t support OO (eg Lua)
1 Like

I note that you ignored my response to your false claims from two months ago, and instead you choose to repeat them here.

Number 1, 2, 3 and 4 draw a false boundary between C and C++. With regard to these items, there is no significant difference between C and C++. Your claim makes you seem a little inexperienced, or otherwise just biassed?

Support for interop and ease of developing bindings is somewhat better with C, no dispute. But C lacks many significant advantages of C++ also. C++ has some significant disadvantages that can be avoided by carefully choosing which features and libraries to ignore. But all this has been said before in this thread. You’re just choosing to ignore it.

@cjheath - Looking at your reply history you haven’t made any replies to my posts until today, which is the first time you have replied to a post I have made.

I would prefer C++ with its type safety, type safe enums, const expressions to reduce define use,…
Also you can eliminate a lot of the memory issues when using smart pointers to the objects and RAII. Those are all critical protections especially in embedded environments.
You can also reduce a lot of code duplication in a type safe way with the proper use of templates.
You can always add a C interface to the library for binding use.

We use C++ on STM32 MCU’s which have a decent ARM compiler.

2 Likes

My earlier response to you was in the Github issue thread. You make a lot of arguments against anything that you think will impede the world dominance of Kotlin. I’m glad you like Kotlin, I think it’s a wonderful thing, but it’s not for everybody, and I don’t think your time is well spent attacking anything that’s not Kotlin.

@cjheath - Due to some of your posts being off topic I will not be making any further replies.

Some software products are deeply integrated with C, specific compiler and specific version, adding more compilers can be complicated