I'm curious, never had a look at Ada, can you elaborate?
I'm curious, never had a look at Ada, can you elaborate?
General lack of dumb C stuff like switch fallthrough, null terminated strings (Arrays in Ada are passed with fat pointers), undefined behavior, no need for memcpy, no preprocessor bullshit etc.
Ada is more like C++ in functionality so it has Generics, Tasks (Threads), Exceptions, Packages, Strong types, Design by contract etc (All much much saner than C++ stuff)
Despite all of the features it's very embedded friendly. Language allows you to disable features you dont wont with Restrictions Pragma (Very long list of restrictions you can apply: https://docs.adacore.com/gnat_rm-docs/html/gnat_rm/gnat_rm/s...). You can also fairly easily change runtimes: https://docs.adacore.com/gnat_ugx-docs/html/gnat_ugx/gnat_ug....
> Ada is better than C
> lack of dumb C stuff
Back to your comment, strong types and generics look super nice for embedded. Not sure I would like fat pointers, exceptions and threads in my embedded code though.
Sorry about that, English is not my first language so i might sound rude sometimes. I actually dont hate C, but if you used it you know its flaws. I think stuff i mentioned about C is objectively bad, hence why i called them dumb stuff.
>Not sure I would like fat pointers, exceptions and threads in my embedded code though
Fat pointers are just pointer + size of an object. You have to pass array size anyway, so its just convenient. Obviously, if you need to just pass a pointer there are ways to do that.
As for exceptions and threads: As i said, you can disable or modify them just by using Restrictions pragma. Its a language defined thing. For example, Ada 2022 defines two profiles for safety-critical hard real-time computing:
https://en.wikipedia.org/wiki/Ravenscar_profile http://www.ada-auth.org/standards/22rm/html/rm-d-13.html
No offense taken, not a native here either ;-)
> if you used it you know its flaws
Indeed, I've been using C for almost 20 years now. I won't say it's without flaw for sure, it has its quirks, but overall I do think it's quite okay for the job.
> Fat pointers are just pointer + size of an object
Yeah I know what fat pointers are, I even resort to handcraft some form in C for some neat performance hackery on x64.
But the thing is, we're talking embedded here. Most ucontrollers I use have 8b address space, no MMU or any form of virtual memory, separated instruction/data bus (MVHA). That kind of thing don't play well with funky fat pointers.
Sure if your definition of embedded is "64b ARM" all is good, but I guess we're on a spectrum.
Exceptions are pretty much non existing as well, since that would require some form of runtime, which you often just cannot afford on a small chip (if not just form the sheer size of it).
Threading is a no go as well. To get threads, or any form of multitasking really, you have to rely on an operating system, which by definition is a bit weird to have on an embedded IC.
You can definitely use Ada on 8bit microcontrollers, for example on 8bit AVR: https://docs.adacore.com/gnat_ugx-docs/html/gnat_ugx/gnat_ug...
You can make runtime as small as you want.
As for exceptions and threads: I mentioned them because thats what comes to mind first, there are more benefits obviously.
https://learn.adacore.com/courses/advanced-ada/parts/data_ty...
http://www.ada-auth.org/standards/22rm/html/RM-13-1.html
Wouldn't it be nice in C to be able to define how a struct is laid out in the machine representation? In Ada, you can and it is part of the standard, so it is portable:
https://learn.adacore.com/courses/advanced-ada/parts/data_ty...
// Ada
for Day use (Mon => 2#00000001#,
Tue => 2#00000010#,
Wed => 2#00000100#,
Thu => 2#00001000#,
Fri => 2#00010000#,
Sat => 2#00100000#,
Sun => 2#01000000#);
// C++
enum Day {
Mon = 0b00000001,
Tue = 0b00000010,
Wed = 0b00000100,
Thu = 0b00001000,
Fri = 0b00010000,
Sat = 0b00100000,
Sun = 0b01000000,
};
As for the record representation, my understanding is that it is equivalent to having a normalized __attribute__((__packed__)), where smart compiler padding is disabled and you can arbitrarily decide the memory layout of your struct? procedure Enable_USB_Clock is
begin
Registers.PMC_Periph.PMC_SCER.USBCLK := 1;
end Enable_USB_Clock;
Example taken from here: https://learn.adacore.com/courses/Ada_For_The_Embedded_C_Dev...