Functional Programming Methodology

As I am learning to write more complex programs, I am wondering how to optimize the code and also make it as readable and modular as possible.

Essentially I want everything to be done (object instantiation and sensor readings) inside functions with a global variables header file. Is this possible without significantly slowing performance?

For instance, if I have a light sensor function, I want to instantiate the light sensor object inside the function each time it is called, and then of course the object is destroyed after each call. I want to do this instead of creating objects and variables before or inside of void setup(). This would go for all of my various sensor readings and the actions that follow, e.g. actuators, relays, etc.

Seems like this would be the best memory management approach, but maybe this is overkill and slows down runtime?

Thanks!

wheemzy:
Essentially I want everything to be done (object instantiation and sensor readings) inside functions. Is this possible without significantly slowing performance?

Even if we are talking specifically about objects associated with physical devices, like LEDs, sensors, servos, motors, serial channels, and so on, there's still no definitive answer to that question.

Each C++ object is usually more than just a bunch of interface functions. It also stores data: some internal persistent state. Every time you destroy an object you lose its state. Every time you create an object, it begins with a clean state.

The question is: is the state of your object discardable? Can you afford to lose the state of your object between function calls? If you cannot, then you will have keep that object alive as long as you need it alive, even between function calls. But if you can afford losing that state (maybe you don't care about it, maybe your know how to restore it afterwards) then yes, you can just declare the object locally.

For example, let's say you have an object of some very primitive 'Led' class, which just attaches to some output pin and has on() and off() functions to set that pin to HIGH and LOW. The state of that object is probably just its pin number and it is effectively discardable. You can always recreate it and reattach it to the same pin. I'd even say that declaring such object locally is THE right thing to do.

A more complicated Led class, which is, say, designed to support millis()-based blinking/fading functionality for a LED will normally have much more elaborate state. It will store additional data responsible for handling timing/blinking/fading behavior. You won't be able to constantly destroy/create such objects, since that will completely disrupt their timing-based behavior.

The Servo library does even more: when you create a Servo object and attach it to a pin, this pin is registered in an timer-interrupt-based pulse generator. This generator is responsible for maintaining PWM signal at the pin, thus forcing the servo to hold its last set position. If you destroy the object, the pin is unregistered. Servo no longer receives the signal and no longer holds its position.

Things like that is what you have to keep in mind.

Some objects can be easily destroyed and recreated at any time. Some cannot and should not be.

wheemzy:
For instance, if I have a light sensor function, I want to instantiate the light sensor object inside the function each time it is called, and then of course the object is destroyed after each call.

If all your object does is instantaneous readings of sensor data, then this is most likely possible.

But if your object also performs some kind of internal batch-reading-and-buffering of the data, then it is a completely different story. You will lose all data buffered inside the object, unless you read it all before destroying the object.

Also, does your object perform some kind of initialization of the sensor in the constructor and de-initialization in the destructor? If so, then creating and destroying it every time in your function might be a bad idea.

These are the factors to consider. There might be many other factors.


To put it differently, one can say that there are at least two kinds of classes (there are more, actually):

  • Classes, which represent and reflect physical entities (LEDs, servos, motors etc.). They can also extend end enhance physical entities (make LEDs blink, make servos hold etc.). Object of such classes are intimately associated with their physical counterparts. They are joined at the hip, so to say. These object must exist as long as the physical entity exists (and as long as your program runs). You cannot just freely create and destroy such objects on a whim.

  • Classes, which represent interactive sessions with physical entities. They represent mere seances of communication, they represent communicative channels. A communication session begins and ends, while the entity continues to exist. Objects of such classes are created when you begin your communication session and destroyed when you end the session. Later you can do it again to start and end another session and so on.

The aforementioned Servo class falls into the first category. Your sensor class most likely belongs to the second one.


In the end it all boils down to the same basic idea. If some piece of memory holds data that you will need for an extended period of time, then you have no choice but to keep that memory occupied as long as you need that data. If some piece of memory holds data that you need for only a short/limited period of time, then C and C++ offer you many different opportunities to optimize memory usage and make sure that memory is not wasted. It includes declaring objects locally, it includes manual management of dynamic memory, it includes "multiplexing" memory usage with unions and/or placement-new, it includes many other techniques.

Coding Style is extremely subjective.
For every reply you get here there will be slight variations (or really big ones!)

The goals are manyfold - and infinite, because every project is unique.

  • To compile correctly
  • To deliver the required functionality
  • To communicate the intent for future debugging & review, or developers to pick-up - involves structure, layout and in many cases - conventions have evolved for simple re-use of standard codigh elements (for, while, do, switch-case, if-else and so-on)
  • Schematics to look pretty with logical arrangement and (standardised) symbols.

I think my project is an example of ‘Arduino way’ of modularity

https://github.com/jandrassy/Regulator

wheemzy:
Essentially I want everything to be done (object instantiation and sensor readings) inside functions with a global variables header file. Is this possible without significantly slowing performance?

For instance, if I have a light sensor function, I want to instantiate the light sensor object inside the function each time it is called, and then of course the object is destroyed after each call. I want to do this instead of creating objects and variables before or inside of void setup().

Why ?

IMHO programs should be written so that they are easy to develop, debug and maintain. I try to write my programs so I will be able to understand them in 6 months time with a single read-through of the code - but I often don't succeed.

Also IMHO where and when objects are created or destroyed is not itself of any importance.

Indeed the business of destroying and re-creating objects can lead to memory wastage and ultimately a program crash in the small memory of an Arduino. While it may seem like poor practice to a programmer that is used to PC programming style the use of global variables and objects has the advantage of making the Arduino memory usage very obvious to and manageable by the programmer.

The first priority is to write a program that works.

...R
Planning and Implementing a Program