Can you instantiate single function of a class?

Hello everyone,

Recently I got the idea that I want to build a library. I want it to work as the Standard Library of a PLC programming environment, where we have commonly used functions, easily available.

Basically my goal is to replicate the PLC programming environment, so I can work in an environment that is common for me.

I created the files standard.cpp and standard.h - body and header files of my library. The compilation works just fine, and I suppose it would work if I booted it now.

However the namespace annoys me.

standard.h:

// ************************************************************
// Header
// ************************************************************
#ifndef standard_h
#define standard_h
#include "Arduino.h"

// ************************************************************
// Standard class
// ************************************************************
class Standard {
  private:
    
  public:
    Standard();
    void TON(bool IN, unsigned long PT, unsigned long ET, bool Q);
};

#endif

// ************************************************************
// ************************************************************

standard.cpp:

/* 
INFORMATION:
  Author:         Christian Ritmann
  Date created:   12th Oct. 2019
  Last edited:    ---
  Location:       Denmark
  
DESCRIPTION:
  Makes a timer that does not interrupt program execution.

  Upon bool true input on "IN", start a timer. Upon counting 
  to the value of the input time "PT" milliseconds, return 
  true on Q. Else return false. Output will stay true until input 
  "IN" is false. Resetting IN input before timer is done
  will reset accumulated time. Outputs Elapsed Time on ET when 
  input is active.

  This program is made as an attempt to replicate PLC TON-
  function block (IEC 61131-3 library).

CHANGELOG:

  12th Oct. 2019:
  - Class created
  
*/

// ************************************************************
// Include libraries
// ************************************************************
#include "Arduino.h"
#include "standard.h"

// ************************************************************
// Standard class main file
// ************************************************************
// Constructor
Standard::Standard() {}

// Time On Delay
void Standard::TON(bool IN, unsigned long PT, unsigned long ET, bool Q) { 

  static unsigned long TimePrevious;
  static bool StartFlag;
  
  // STORE SYSTEM TIME ON INPUT
  if(IN and !StartFlag) {
    TimePrevious      = millis();
    StartFlag         = true;
  }
  
  // RESET START FLAG, RETURN FALSE
  if(!IN) {
    StartFlag         = false;
    
    Q = false;
  }

  // CHECK IF ASSIGNED TIME HAS PASSED, ASSIGN RETURN VALUE TRUE
  if(millis() - TimePrevious >= PT and IN) {
    Q = true;
  }

  // RETURN ELAPSED TIME
  if(IN) {
    ET = millis() - TimePrevious;
  }

  // RETURN 0 IF INPUT IS FALSE
  else {
    ET = 0;
  }
}

// ************************************************************
// ************************************************************

To call the Timer On Delay - TON() - I now have to define an instance of Standard, and call it by "Standard_Instance.TON()". Now the problem is:

My plan is to expand the standard library to maybe 20-30 functions. But I don't want to instantiate all 20-30 functions every time I need say a timer or a counter. I would like to be able to instantiate the timer function only, even if I need multiple instances at once.

Is there a solution to this problem?

Best regards
Christian

*EDIT

I see I got a little carried away with the post, and it ended up not really matching the title.

But what is described is what I mean. I just found it a little difficult to phrase since English isn't my first language, and programming language definetely isn't my first language :slight_smile:

I edited the title to match the topic.

when you create a program and are generating the final binary, the compiler gets rid of unused functions code

Also this is my first time ever creating a class. Any feedback and advice would be much appreciated.

Hey landsmand! :slight_smile:

You could use something as simple as a namespace:

//Implementation of a namespace:
namespace MYNAMESPACE {

  int getSomeValue() { return 123; }

}

//Using the namespace, method 1
#include <mynamespace.h>
...
int theValue = MYNAMESPACE::getSomeValue();


//Using the namespace, method 2
#include <mynamespace.h>
using namespace MYNAMSPACE;
...
int theValue = getSomeValue();

Further reading.

On the language:

you don't instantiate a function, you create an instance of a class. that reserves space for the attributes (variables) describing such instance. the functions attached to the class are just regular code - used in a clever way by the compiler. You don't get 10 times the same function code in memory if you instantiated 10 times your class

may be what you want is 10 different classes (or a hierarchy) for various use cases

——

for your code, that's a good start. Don't hesitate to use meaningful descriptive variable names and namespace, and question yourself if you want static variables within the functions or instance variables.

J-M-L:
question yourself if you want static variables within the functions or instance variables.

Using instance variables in a class may result in wasted memory if only one method in a class is needed. Using static variables within the functions will eliminate this. Using static variables, on the other hand, will only allow "one instance" of a function to be called. Sollution to both problems is to pass all required variables (or a struct) to the function as argument(s).

Static variables made sense before you transplanted your function into a class. Now, I suspect, you should make them class instance variables.

Danois90:
Using instance variables in a class may result in wasted memory if only one method in a class is needed. Using static variables within the functions will eliminate this. Using static variables, on the other hand, will only allow "one instance" of a function to be called. Sollution to both problems is to pass all required variables (or a struct) to the function as argument(s).

that's not an OO approach... then don't use a class, just build a library of functions...

Danois90:
Using instance variables in a class may result in wasted memory if only one method in a class is needed. Using static variables within the functions will eliminate this. Using static variables, on the other hand, will only allow "one instance" of a function to be called. Sollution to both problems is to pass all required variables (or a struct) to the function as argument(s).

This is the problem that I wanted to avoid - consuming unnecessary memory for unused variables (by defining them as private for the class rather than inside the functions using them, so that only used functions have their variables instantiated)

In PLC, functions have "temporary" variables, which means they reset for every cycle or call. Since I'm going to try to make the entire program cyclic, like in PLC, I want to avoid the accumulated time to be reset for each cycle. Does the variable has to be static for this?

.. og dav du :slight_smile:

Thanks for the advice

if you have a normal instance variable (public or private), you'll get a copy (memory allocated) for each instance of the class.

You can also have static (class) variables, then you'll get only ONE for all the instances (shared) (but static members exist even if no objects of the class have been instantiated! Much like global variables, they are created when the program starts, and destroyed when the program ends)

if you use a static variable inside a member function (ie it's a variable that will survive across calls, with a scope limited to that function), then this variable is shared across all instances of that class --> that's where you need to ask yourself if this is the intended behavior.

not saying it's wrong, saying you need to understand what you get

J-M-L:
that's not an OO approach... then don't use a class, just build a library of functions...

I would like to be able to use multiple TON functions at once. This is why I was originally suggested to create a class.

Eg.:

TON(100);
TON(1000);
TON(30000);

A program running three different timers at once, re-using the same code, but not overwriting each other. This wouldn't be possible with just a function, would it? Then I'd need multiple instances of a class?

Eg.:

Name1.TON(100);
Name2.TON(1000);
Name3.TON(30000);

My problem is that I would like to be able to call them like this:

Standard.TON timer1;
Standard.TON timer2;
Standard.TON timer3;

timer1(100);
timer2(1000);
timer3(30000);

So it replacates the use from PLC programming language.

Is this possible?

The value of local static variables are preserved after the method exits. If you want the variables to reset for each call, static variables are not what you want.

int testStatic() {
  static int result = 0;
  result++;
  return result;
}

Serial.println(testStatic()); //1
Serial.println(testStatic()); //2
Serial.println(testStatic()); //3

I would like to be able to use multiple TON functions at once. This is why I was originally suggested to create a class.

Yes, that's what classes are for. Design them to use minimal memory. Ask yourself what a TON requires, that will be your instance variables.

Ritmann:
So it replacates the use from PLC programming language.

I would suggest to get over it and program in C++ if you want to play directly with Arduino

J-M-L:
if you use a static variable inside a member function (ie it's a variable that will survive across calls, with a scope limited to that function), then this variable is shared across all instances of that class --> that's where you need to ask yourself if this is the intended behavior.

not saying it's wrong, saying you need to understand what you get

That is definitely not the intended behavior. Thank you!

If I remove "Static" and define the as:

unsigned long TimePrevious;
bool StartFlag;

Will the time stamp stored in TimePrevious survive multiple program cycles, or reset for each cycle?

Ritmann:
Will the time stamp stored in TimePrevious survive multiple program cycles, or reset for each cycle?

see answer #9

if you want something to survive, it can't be a simple local variable. it needs to be allocated outside the stack and its lifetime will depends if it's a global variable (lifetime = the one of your program running) or associated to an instance (lifetime = when the instance exists)

Ritmann:
Is this possible?

Sounds like you have the right approach, but the wrong mindset. You should encapsulate each timer in a class and initialize the timer using the constructor:

//SomeTimer.h + *.cpp

class SomeTimer {
private:
  int var1, var2;

public:
  SomeTimer(int v1, int v2)
  {
    var1 = v1;
    var2 = v2;
  }

  void TON()
  {
    Serial.print(var1);
    Serial.print(" ");
    Serial.println(var2);
  }
}

//Using the class
#include <SomeTimer.h>

SomeTimer timer1(10, 20);
SomeTimer timer2(50, 60);

...

timer1.TON(); //Prints 10 20
timer2.TON(); //Prints 50 60

That is the best way to re-use the same code for handling multiple variables.

Danois90:
...

  SomeTimer(int v1, int v2)

{
    var1 = v1;
    var2 = v2;
  }

side note: this is usually written as ...SomeTimer(int v1, int v2) : var1(v1), var2(v2) {}

cf Constructors and member initializer lists

J-M-L:
Yes, that's what classes are for. Design them to use minimal memory. Ask yourself what a TON requires, that will be your instance variables.
I would suggest to get over it and program in C++ if you want to play directly with Arduino

Since PLC is very expensive in licenses etc., I'd hoped I could create a similar environment at home for practicing programming for my job as automation engineer (plc programmer), and to use the Arduino platform to improve my skills in electronics as well.

have you checked Open PLC?

Arduino is a target "SLAVE DEVICE"

see this video

J-M-L:
have you checked Open PLC?

Arduino is a target "SLAVE DEVICE"

see this video

I had no idea.

Thanks!