Why is the Arduino programming environment designed like this?

There is a “style” (Protocol? Approach? Characteristic?) of C++ programming in the Arduino environment which I don't understand and find very annoying. I've encountered it with Serial, SD, Wire – almost all of the standard libraries.

This tendency is to automatically instantiate an instance of a class (or classes) simply by including its corresponding '.h' file. Want a serial port in your project? Just include Serial.h, you automatically have an instance of the SerialClass in your code. Want a card reader in your system? Just include SD.h. You've automatically got an instance of the SDClass in your code. One doesn't even have to declare it, it's 'just there' in the background, as every Arduino programmer knows (or maybe they don't?) when they begin their project code with Serial.begin() without ever having to declare an instance of the SerialClass.

I can understand that from the point of view of 'simplicity', 'easy to learn', etc. this may be desirable. As long as one is writing short and simple projects in a functional programming style, it's acceptable. But when you graduate to larger and more complex OO projects using C++ (or Objective-C or C# or) it's really a nuisance, even an obstacle.

Here is an example. My current project has three SD card readers, i.e., three separate file systems (like having three hard drives). I wrote my own class for everything I need and named it FileSystem, which includes declarations in the header file (FileSystem.h) like:

SDClass *fileSystem;
Sd2Card *memoryCard;
SdVolume *volume;
SdFile *root;

and statements in the constructor in the implementation file (FileSystem.cpp) like:

fileSystem = new SDClass();
memoryCard = new Sd2Card();
volume = new SdVolume();
root = new SdFile();

I instantiate three instances of 'FileSystem':

FileSystem *fs1,*fs2,*fs3;

fs1 = new FileSystem();
fs2 = new FileSystem();
fs3 = new FileSystem();

This is all working BTW. But the annoying part is that the 'invisible' instance of the SDClass which was automatically instantiated by including SD.h IS STILL THERE, unused, taking up memory. How does one delete these 'background' class instances without explicitly messaging 'delete(&SD);'? Who would think of doing that, deleting something you never created?

This is obviously more of a 'philosophy of programming' or 'psychology of programming' issue than something imminently important or pressing. But if anyone out there can explain to me why the Arduino environment is twisted this way I would appreciate hearing your opinion. It runs counter to everything I have learned in my career as a programmer, and I've been programming computers much longer than most of the people who read this forum have been alive. :slight_smile:

Oh, and yes, I'm a little restless, quarantined in Spain because of the virus, so please don't take offense, I'm not trying to bash anybody or anything.

odlumb:
This tendency is to automatically instantiate an instance of a class (or classes) simply by including its corresponding '.h' file.

The purpose is to make things simple for beginners.

...R

This is interesting. As a guy who is not new to OOP but is new to Arduino and to C++, I didn't realize that this was happening. When I include a .h file I always instantiate the objects that I was to use, which I will continue to do. However, this "hidden" object that is automatically there, how does that work? For example, if the .h file contains a class called CoolNewThing is the hidden object just called CoolNewThing?

I can see what you are saying with Serial, I guess I just assumed that there was a set of objects that the Arduino implementation made available, I never really thought about how it got there.

Since Arduino is geared toward maker types there are compromises to help out the hobbyists. It is annoying, however, to those of us whose vocation is software engineering. Indeed, the code I encounter on this forum makes me cringe (even code in some of the libraries) but I am reminded of the schooled musician who teaches beginner band.

I suppose if it becomes a real issue you could modify the libraries not to instantiate an instance. Alternatively, you could use the instance instantiated by the library but that messes up your naming (thus readability) unless you use a #define, which I also find distasteful.

I'd guess the library author never expected anyone to use multiple SD cards. Just out of curiosity, what is that for?

In the libraries where it's obvious multiple instances would be needed (e.g., Servo), they don't do this.

odlumb:
I can understand that from the point of view of 'simplicity', 'easy to learn', etc. this may be desirable.

I'm sure that's the reason. For a beginner, that extra line of code is very confusing and offers one more opportunity for them to make a mistake and have a bad first experience. It's the same idea as the automatic function prototype generation.

Maybe user should be directed to include an instantiation just below the include in their sketch? Also done that way in the examples? A lot of people are just copying examples anyway. If it's in the example they would just copy and use it that way.

The libraries just haven't had the stewardship that the core has had.

aarg:
If it's in the example they would just copy and use it that way.

Surely you've been around here long enough to know how often beginners don't manage that.

pert:
I'd guess the library author never expected anyone to use multiple SD cards. Just out of curiosity, what is that for?

There are only two I actually use, the third one exists just because I had the parts hanging around and I wanted to 'prove the point'. One system is a data logger, mostly for errors, the other system holds gigantic data tables which are otherwise impossible given the RAM limitations of a Mega 2560.

Is the reason for having two cards so you can pull one to get the log without needing to mess with the one that has the data tables?

pert:
Is the reason for having two cards so you can pull one to get the log without needing to mess with the one that has the data tables?

That was kind of the original idea, although in practice the log file never gets big enough that I can't just dump the info to Serial and delete the file. I have to open the case to retrieve the card anyway, so in practice it's not so easy. But I have been doing embedded real-time programming for over fifty years, and my collective experiences with debugging problems caused by memory limitations have taught me to design very wide margins into any system.

mmitchellmoss:
However, this "hidden" object that is automatically there, how does that work? For example, if the .h file contains a class called CoolNewThing is the hidden object just called CoolNewThing?

Nothing is hidden. Typically:

In CoolNewThing.h

extern CoolNewThing aCoolThing;

In CoolNewThing.cpp

CoolNewThing aCoolThing;

gfvalvo:
Nothing is hidden. Typically:

In CoolNewThing.h

extern CoolNewThing aCoolThing;

In CoolNewThing.cpp

CoolNewThing aCoolThing;

Okay, I see. So it isn't really something that happens automatically, it is just something that the class designer seems to do pretty often?

aarg:
Maybe user should be directed to include an instantiation just below the include in their sketch? Also done that way in the examples?

That would cause problems for newbies with objects like 'Serial' whose class depends on which board you're compiling for.

If you don't like how a given library works, feel free to modify your copies, to remove the auto-generated instances. Whining about it here is rather pointless.

Regards,
Ray L.

Why is the Arduino programming environment designed like this?

The Arduino programming environment has not been designed like this, rather it is some library writers who have chosen to implement their libraries in this way

UKHeliBob:
The Arduino programming environment has not been designed like this, rather it is some library writers who have chosen to implement their libraries in this way

wasn't this done by the same group of people (Arduino ('designers'))? the IDE, the core, the core libraries (SPI, Wire, SoftwareSerial, Ethernet...)?

Juraj:
wasn't this done by the same group of people (Arduino ('designers'))? the IDE, the core, the core libraries (SPI, Wire, SoftwareSerial, Ethernet...)?

Yes, but not all the "Standard Libraries"... EEPROM, Liquid Crystal, SD, GSM, Servo, IR... and it has created some confusion as libraries proliferated for the same devices. There isn't any real "seal of approval" list which is a shame. Some of the stuff that's listed in the Reference section is outdated or better alternatives exist, or it's just plain hard to navigate to, hard to download and install (for a beginner).

Imagine being a beginner and going here:
https://www.arduino.cc/en/Reference/LiquidCrystalOkay, a nice description but where do I get more information or download the library? Or, am I just out of touch and should be using the library manager (I admit I haven't really looked at that)?