C++, Ada, ...

What do you think about different languages than usual C for embedded systems?

I mean C++, Ada but also Python. Always more powerful embedded processors are coming, so I expect new and modern languages will enter in the embedded world.

Hardware are cheaper and more powerful than ever, but software stays expensive. New and modern languages could reduce the software cost, because they are simpler than C and much more similar to desktop/server programming paradigm.

We embedded sw developers were lucky: electronics and technologies change rapidly, but sw for embedded has changed slower than desktop/mobile sw. Think of mobile app developers: maybe they already changed IDEs, tools and languages ten times in a few years. C language for embedded is today very similar than 10 years ago.

However I think this situation for embedded developers will change in the very next years. And we will be forced to learn modern technologies, such as new languages and tools. Is it ok for me to study and learn new things... but it will be more difficult to acquire new skills for real jobs.

What do you think?

Reply to
pozz
Loading thread data ...

You should probably add Rust to your list - I think its popularity will increase.

Python is great when you have the resources. It's the language I use most on PC's and servers, and it is very common on embedded Linux systems (like Pi's, and industrial equivalents). Micropython is sometimes found on smaller systems, such as ESP32 devices.

Ada involves a fair amount of change to how you work, compared to C development. (Disclaimer - I have only done a very small amount of Ada coding, and no serious projects. But I have considered it as an option.) I really don't see it becoming much more common, and outside of niche areas (defence, aerospace) it is very rare. Programming in Ada often takes a lot more effort even for simple things, leading quickly to code that is so wordy that it is unclear what is going on. And most of the advantages of Ada (such as better typing) can be achieved in C++ with less effort, and at the same time C++ can give additional safety on resources that is harder to get on Ada. (But Ada has some nice features introspective that C++ programmers currently only dream about.)

C++ is not uncommon in embedded systems, and I expect to see more of it. I use it as my main embedded language now. C++ gives more scope for getting things wrong in weird ways, and more scope for accidentally making your binary massively larger than you expect, but with care it makes it a lot easier to write clear code and safe code, where common C mistakes either can't happen or you get compile-time failures.

It used to be the case that C++ compilers were expensive and poor quality, that the resulting code was very slow on common microcontrollers, and that the language didn't have much extra to offer small-systems embedded developers. That, I think, has changed in all aspects. I use gcc 10 with C++17 on Cortex-M devices, and features like templates, strong enumerations, std::array, and controlled automatic conversions make it easier to write good code.

Reply to
David Brown

Interesting. Could you give a quick outline of that?

Reply to
Tom Gardner

+1.

I've used C++ for over 30 years, but Rust is going to rule. It's not really any harder, but vastly safer, especially for parallel coding.

CH

Reply to
Clifford Heath

Another +1 for C++. We started using C++ for embedded ~25 years ago, and the tool quality (and language) is vastly better now. Main problem using C++ is lack of available qualified staff - too many still only trained in C. C++, even more than C, *requires* painful amount of knowledge of how things work under the hood to use safely, not a good quality for any tool in any realm. But for *qualified* developers, C++ certainly gives faster development, produces better (ie faster/smaller) code, and generally improves life (compared to C).

Reply to
Dave Nadler

That depends, I guess, on what one considers "simple", and also, of course, on how familiar one is with the languages.

Perhaps it is time to link once again to the experience of C versus Ada in an introductory embedded-programming class using a model rail-road example, where the students using Ada fared much better than those using C:

formatting link

I am (as you guessed) an Ada fan, and find it a pleasure to write, even if it takes more keystrokes than the equivalent in C.

For embedded systems in particular, I find portability to be a great advantage of Ada. With few exceptions, the embedded program can be exercised on the development host, and if the target supports the standard Ada tasking system (or a subset of it), this applies even to multi-threaded programs (without the need to emulate some embedded RTK/OS on the host).

According to the link above, the main Ada advantage was the ability to define one's own problem-oriented scalar types, such as integers with specific value ranges. AIUI, this is not easily done in C++.

Can you be more specific on those points, please?

AdaCore provides the gcc-based GNAT Ada compiler for several embedded targets, free to use for open-source projects: libre.adacore.com.

Commercial projects can use Ada on other targets by means of the (different) AdaCore compiler that generates C code as an intermediate representation.

Reply to
Niklas Holsti

Yes indeed. Especially when coupled with inexperience leading someone to believe they understand C or C++.

Your other (valid) caveats and points snipped for brevity.

Reply to
Tom Gardner

Which part?

My understanding of Ada classes is that, like Pascal classes, you need to explicitly construct and destruct objects. This gives far greater scope for programmers to get things wrong than when they are handled automatically by the language.

On the other hand, some of Ada's type mechanisms make it a lot easier to make new types with similar properties while remaining distinct (such as subranges of integer types). You can do that in C++, but someone needs to make the effort to make the appropriate class templates. Thus these are more often used in Ada coding than in C++ coding.

On the third hand (three hands are always useful for programming), the wordy nature of type conversions in Ada mean programmers would be tempted to take shortcuts and skip these extra types.

Reply to
David Brown

I wouldn't include C++ in the list of "modern languages". One might as well use C.

As for the "more modern" languages (Python, C#, Java etc) I've used most of them and maybe it's the old man in me speaking, but I haven't felt any inherent important advantages in using them. Their success is mostly due to better support by popular development tools.

These days, smarter people praise functional programming languages (Haskell, Clojure, etc...). They promise tangible advantages compared to imperative languages, especially for maintainability and reliability. But I think that even if they will gain popularity, years would pass before you will see real applications in the embedded world.

Python is a "hybrid", it can be also used as a functional programming language, and it will probably gain popularity in embedded systems.

--
Fletto i muscoli e sono nel vuoto.
Reply to
dalai lamah

Are there no newer examples? While this study was interesting, it is some 30 years out of date and compares and old version of Ada with an old version of C (perhaps not even C90). I'd rather see the pros and cons of Ada 2012 compared to C++17.

I had no need to guess - it's not the first time you have posted about Ada here! I'm glad that someone with your Ada qualifications can chime in here, and can correct my if I'm wrong.

For suitable targets, I can see that being useful. C and C++ can be used on a wider range of targets, and with a wider range of RTOS (if any). Of course, code for widely differing target systems is often very different anyway, so portability is not always a concern.

Sure it can be done in C++.

You can make types with specific ranges (with compile-time checks where possible, optional run-time checks otherwise). You can choose which operations you allow on them, and how they combine (so that multiplying a speed and a time give you a distance automatically, but adding them is not allowed). You can make integer types with different overflow behaviour (wrapping, saturating, throwing errors, unspecified behaviour, undefined behaviour) that can be used as easily as normal integers, and mixed if and only if it is safe to do so or you make it explicit. You can make array types that are indexed by enumerated types. It's all possible - more so that in Ada, AFAIK.

Where you have a difference, however, is that many of the most beneficial cases (such as strong subrange types) are simple to use in Ada and built into the language, and therefore they are often used. In C++, you need to find a suitable template library or make things yourself, giving a much higher barrier to use.

A very interesting distinction when looking at language features and safe coding is how much people /could/ use safety features, and how much they /do/ use them. For example, with C programming you can get strong type safety as long as you wrap all your new types in structs. The compiler will complain for type mistakes, just as it would in Ada - but the /use/ of such types is often very inconvenient in C.

For the first point - my understanding is that in Ada, when you have classes you need to manually call constructor and destructor (initializer and finalizer) functions. RAII is thus harder, and it is as easy to make mistakes as it is in C (with malloc and free). Does Ada have the equivalent of std::unique_ptr, std::shared_ptr and other smart pointers, or container classes that handle allocation?

For the second point, I am thinking of things like type attributes. I would /really/ like C++ enumerations to have something matching the "first" and "last" attributes! AFAIK, C++ won't get this until reflection is added, probably not until C++26.

This means that Ada suffers from a similar barrier to adoption that C++ used to do. Big companies will happily pay the cost for the tools that they think will lead to better development efficiency or reliability. Smaller ones will have a much harder time trying to justify the expense, especially as they will often have few developers who can use the tools. A move from C to Ada is compounded by needing a complete change of the code - with C to C++, you can re-use old code, and you can also use a few of the C++ features rather than moving wholescale (though of course you also miss out on corresponding benefits).

Reply to
David Brown

If you mean automatic allocation and deallocation of storage, Ada lets you define types that have an "initializer" that is called automatically, and can allocate memory if it needs to, and a "finalizer" that is automatically called when leaving the scope of the object in question. The finalizer does have to explicitly deallocate any explicitly allocated and owned resources, and it may have to use reference counting for that, for complex data structures.

AUI that also holds for C++, although I believe recent C++ standards may have simplified the definition and use of reference-counted data structures.

(That relative ease in Ada was the point of my other response -- more to come on that.)

Huh? A normal conversion in C is written "(newtype)expression", the same in Ada is written "newtype(expression)". Exactly the same number of characters, only the placement of the () is different. The C form might even require an extra set of parentheses around it, to demarcate the expression to be converted from any containing expression.

Of course, in C you have implicit conversions between all kinds of numerical types, often leading to a whole lot of errors... not only apples+oranges, but also truncation or other miscomputation.

Reply to
Niklas Holsti

I have none to hand, at least.

I would call it "30 years old". Whether it is "out of date" can be debated -- I don't think the basic ideas of the two languages have changed very drastically even in that time.

So would I, but I haven't seen any such studies reported.

I can only point to the biased material at

formatting link

And a recent Ada-adoption story from NVIDIA:

formatting link

but that is more about the AdaCore tools and the SPARK form of Ada than about C-vs-Ada.

Ada can be used with other RTOSses too, although one loses both some ease-of-use advantages and the portability advantage. Typical Ada compilers for embedded systems also let one write Ada programs that do not need an RTOS at all and run with a single thread.

I did not see any mention of range-checked types there. But yes, they can be constructed in C++, but not as easily as in Ada, as it seems we agree. I should have said "/as/ easily" in the quote above.

I admit that C++ templates allow the programming of more compile-time activities than Ada allows.

Yup.

Indeed.

Answered in another message. The Ada "controlled" types have automatically called initializer and finalizer operations. They can be used to implement smart pointers, but no smart pointers are built into Ada (perhaps mainly because they would then have to be thread-safe, which would be a lot of overhead for a single-threaded program).

Yes, good point in favour of Ada. I've seen some C++ programs that go to great metaprogramming lengths to define "trait" templates to get the equivalent of the "first", "last", "size" etc. attributes. So it is, again, possible in C++, but not as easy as when it is built-in, as in Ada.

Of course you can move from C to Ada without a full re-write, because all Ada compilers provide inter-linking with C code, and most data structures can be mapped between the two languages. (For some Ada compilers like GNAT, this even holds for C++ and Ada)

In fact, there is another C-vs-Ada study,

formatting link

where an Ada compiler vendor incrementally moved their Ada compiler from being written in C to being written in Ada, and found a steady increase of quality and decrease of cost-to-repair as modules were moved from C to Ada. But it is from 1995, so perhaps "out of date" :-)

Reply to
Niklas Holsti

I had a little look for this (these discussions are great for inspiring learning!). The impression I got was that it was possible, but what takes a few lines of C++ (excluding whatever work must be done inside the constructor and destructor bodies) involves inheriting from a specific library type. And you don't have automatic initialisation of subobjects and ancestors in a controlled order, nor automatic finalisation of them in the reverse order.

Let's take a little example. And since this is comp.arch.embedded, let's take a purely embedded example of disabling interrupts, rather than shunned dynamic memory allocations:

static inline uint32_t disableGlobalInterrupts(void) { uint32_t pri; asm volatile( " mrs %[pri], primask\n\t" // Get old mask " cpsid i\n\t" // Disable interrupts entirely " dsb" // Ensures that this takes effect before next // instruction : [pri] "=r" (pri) :: "memory"); return pri; }

static inline void restoreGlobalInterrupts(uint32_t pri) { asm volatile( " msr primask, %[pri]" // Restore old mask :: [pri] "r" (pri) : "memory"); }

class CriticalSectionLock { private : uint32_t oldpri; public : CriticalSectionLock() { oldpri = disableGlobalInterrupts(); } ~CriticalSectionLock() { restoreGlobalInterrupts(oldpri); } };

You can use it like this:

bool compare_and_swap64(uint64_t * p, uint64_t old, uint64_t x) { CriticalSectionLock lock;

if (*p != old) return false; *p = x; return true; }

This is the code compiled for a 32-bit Cortex-M device:

The use of the class here has no overhead compared to manually disabling and re-enabling interrupts.

What would be the Ada equivalent of this class, and of the "compare_and_swap64" function?

C also makes explicit conversions wordy, yes. In C++, you can choose which conversions are explicit and which are implicit - done carefully, your safe conversions will be implicit and unsafe ones need to be explicit.

(C++ suffers from its C heritage and backwards compatibility, meaning it can't fix things that were always implicit conversion. It's too late to make "int x = 123.4;" an error. The best C++ can do is add a new syntax with better safety - so "int y { 123 };" is fine but "int z { 123.4 };" is an error.)

Reply to
David Brown

C made a big leap, IMHO, with C99 - it became a significantly better language, and it became easier to write safe, clear and efficient code than with C90. (C11 and C17 add little in comparison.)

C++ is a completely different language now than it was 30 years ago.

And the tools for both C and C++ have changed hugely in that time.

But some programmers have not changed, and the way they write C code has not changed. Again, it's a question of whether you are comparing how languages /could/ be used at their best, or how some people use them at their worst, or guessing something in between.

As an example of the bias, I looked at the "What constructs exist in Ada that do not have an equivalent construct in C/C++?" page. First off, anyone who talks about "C/C++" as though it were a single language is either ignorant or biased. Some of their points are outdated (C++ has "proper" array types in the standard library), and support for very nice syntaxes for literals). Some are fair enough - strong type checking of arithmetic types needs a good deal more effort (such as shown in the "strong typedef" link from earlier). Some are absolutely a point to Ada, such as named parameters. And the page is missing the "What constructs exist in C++ that do not have an equivalent in Ada?" list :-)

Once you have made appropriate templates, they can be used as easily as in Ada. But such templates are not in the C++ standard library.

C++ has got a lot stronger at compile-time work in recent versions. Not only have templates got more powerful, but we've got "concepts" (named sets of features or requirements for types), constexpr functions (that can be evaluated at compile time or runtime), consteval functions (that must be evaluated at compile time), constinit data (that must have compile-time constant initialisers), etc. And constants determined at compile-time are not restricted to scaler or simple types.

Agreed.

There is a proposal in the works for "metaclasses" in C++, which goes beyond reflection and into code generation. I'm looking forward to that

- it will put an end to a lot of "boilerplate" code. But it's going to take a good while to arrive.

You can move file by file from C to Ada, but you can move from C to C++ by adding the "-x c++" flag to your build or clicking the "compile C code as C++" on the IDE. Then you change as much or as little as you want, when you want.

Reply to
David Brown

That is indeed a useful first question.

A second question is "how easy is it to get intelligent but inexperienced programmers to avoid the worst features and use the languages well?" (We'll ignore all the programmers that shouldn't be given a keyboard :) )

A third is "will that happen in company X's environment when they are extending code written by people that left 5 years ago?"

Reply to
Tom Gardner

Sounds wordy ;)

Reply to
Tom Gardner

Have you looked at the C++ standards documents? There are more than a few words there!

I'm not suggesting C++ is a perfect language - not by a long way. It has plenty of ugliness, and in this thread we've covered several points where Ada can do something neater and clearer than you can do it in C++.

But it's a good thing that it has more ways for handling things at compile time. In many of my C projects, I have had Python code for pre-processing, for computing tables, and that kind of thing. With modern C++, these are no longer needed.

An odd thing about the compile-time calculation features of C++ is that they came about partly by accident, or unforeseen side-effects. Someone discovered that templates with integer parameters could be used to do quite a lot of compile-time calculations. The code was /really/ ugly, slow to compile, limited in scope. But people were finding use for it. So the motivation for "constexpr" was that programmers were already doing compile-time calculations, and so it was best to let them do it in a nicer way.

Reply to
David Brown

All good questions.

Another is what will happen to the company when the one person that understood the language at all, leaves? With C++, you can hire another qualified and experienced C++ programmer. (Okay, so you might have to beat them over the head with an 8051 emulator until they stop using std::vector and realise you don't want UCS2 encoding for your 2x20 character display, but they'll learn that soon enough.) With Ada, or Forth, or any other minor language, you are scuppered.

These are important considerations.

Reply to
David Brown

They are important considerations, indeed.

I'm unconvinced that it is practical to rely on hiring another C++ programmer that is /actually/ qualified and experienced - and wants to work on someone else's code.

The "uncanny valley" is a major problem for any new tech, languages included.

We've all seen the next better mousetrap that turns out to merely have exchanged swings and roundabouts.

Reply to
Tom Gardner

No. I value my sanity.

The useful question is not whether something is good, but whether there are better alternatives. "Better", of course, can include /anything/ relevant!

Infamously, getting a valid C++ program that cause the compiler to generate the sequence of prime numbers during compilation came as an unpleasant /surprise/ to the C++ standards committee.

The code is short; whether it is ugly is a matter of taste!

formatting link

Reply to
Tom Gardner

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.