I've been using arduino for several years now and have a lot of shared code between projects so I'm starting to bundle it into libraries. Up until now I have only used C and C idioms, and I may need to share some of my libs with a friend using a C compiler (no C++).
As such I made a test Arduino library that only uses structs and functions instead of classes. It seems to compile just fine. I know it's trickier for the user because they have to say, instantiate the struct and initialize as two separate steps, and pass the struct as an argument to its related functions rather than calling a class member. But this is only for me and a few friends so I figure that's tolerable if it solves the goal of making it pure C compatible. Am I setting myself up for any technical headaches within the Arduino environment by doing it this way?
Thanks for any suggestions!
No. Convention is that a 'library' is a class, but it is just a convention.
No. Convention is that a 'library' is a class, but it is just a convention.
Utterly wrong! There is no such convention. You simply pick the method which best suits you and the problem.
For example the maths functions (sin,tan,etc) would make no sense as a class.
As far as I can tell the only reason that class are so widely used in the Arduino community is that the how to write a lib example in the learning zone was left unfinished.
Mark
holmes4:
As far as I can tell the only reason that class are so widely used in the Arduino community is that the how to write a lib example in the learning zone was left unfinished.
I haven't read it (I read libraries instead), but I believe you. I would give as a reason, that most libraries exist to support some kind of hardware device. That job is usually best done with OO, one reason is that it makes it easy to use the same code to support multiple devices of the same type. Another is to easily avoid name space collisions with the user sketch.
capsid:
Am I setting myself up for any technical headaches within the Arduino environment by doing it this way?
Yes. But the headaches are not Arduino specific.
C-isms pollute the global namespace.
C-isms lack refined scoping.
C-isms lack access protection.
As you mentioned C-isms lack guaranteed initialization / finalization.
There are undoubtedly more for the list but that should give you a taste. Do yourself and your friends a favor: learn some C++.
However you can use C++ and not actually write a class. However making a class does give you some of the advantages that Coding Badly mentioned.
Sounds good. Thank you!
I went ahead and wrote it in C++ today anyway and figured I'd port it to the friend's C project when I absolutely need to.
using a C compiler (no C++).
Again NO.
C++ is a superset of C. Every thing in C is also in C++. Even the name C++ is a joke! It means C incremented after use!.
To make matters worse any C++ class can (and often is) translated in to old school C. This is how the first implementations of C++ where done.
Mark
holmes4:
C++ is a superset of C.
It is not that simple. You can use only C99 in C++. You can check the wikipedia page for more info.
Here are my 2 cents.
For good encapsulation you don't need classes at all, what you need is a "module": a set of clearly related variables and functions, and some mechanism to hide information from other parts of the code (scoping).
In C, you typically design a public interface and put all the public stuff in a .h header file. Then you create the implementation in the .c file. You can achieve class-like encapsulation (private state and behaviour) by using the static keyword for variables and functions that should only be visible inside that file. And you can also have some sort of polymorphism by creating several implementation files, write client code against the interface, and selectively import the implementation file you want.
For instance, to write a motor library you could first create the header file (motor.h) with two publicly accessible functions (on and off), and write a temporary stub implementation that does nothing but to log to console (stub.c). Then you can write and test the rest of the program depending on the interface. Later you might write the actual motor.c file talking to the motor and replace stub.c with motor.c in the imports. If some other day you need to use a different motor you can write motor2.c and switch the imports.
This is good old procedural programming, which came way before OOP, and not only it is still valid today, but it is frequently used in embedded systems as the programs are usually shorter and simpler than, lets say, desktop or enterprise applications.
OOP was born because there was the need to write larger and more complex apps, and the procedural paradigm was not enough to organize such codebases. With OOP you could for instance have the Motor class implement the IMotor interface, then create a second Motor2.class that extends from Motor and reuses some methods, and switch among implementations at runtime. You can of course use C++ in Arduino but it takes more time to get a good grasp on basic C++ than what it takes to properly learn C. If you don't need complex or advanced features, you could probably achieve the same with plain C. The opposite is also true: there are programmers doing backend development in OO languages that use classes mainly because that's usually the only way to have a module, but these classes very often are just procedural modules in disguise.
1 Like