Are anonymous function or lambda possible with UNO? [YES] [solved]

This is probably easy for many of you, but I am at a loss as to how Lambda/anonymous function work.
While I may not attempt to use this in any of my code in the near future, It intrigues me and I am spending way too much time trying to grasp how to trigger this lambda/anonymous function What am I missing.
I have read many examples but none are geared towards Arduino. I have used similar code in Javascript like JQuery but it isn't quite working for me to grasp what I am missing.

Lambda:

[a](int a) {Serial.print(a);  };

This compiles but I cant get Serial.print(a); to trigger.
I assume it needs to be a part of some other function but how do I make that work?

void setup() {
  // put your setup code here, to run once:

  Serial.begin(115200);
}

void loop() {
  int a =1;
  [a](int a) {Serial.print(a);  };  
  Serial.println(".");
  delay(100);
}

What brought this up is with the ESP8266 and the spi interface as a slave uses this coding. I would like to .understand it enough to possibly use it with the UNO also
ESP8266 Example:

    SPISlave.onData([](uint8_t * _Source, size_t len) {
        SPISlave.setData(_Source);
        Serial.printf("Question: %s\n", (char *)_Source);
    });

Full Code:

/*
    SPI Slave Demo Sketch
    Connect the SPI Master device to the following pins on the esp8266:

    GPIO    NodeMCU   Name  |   Uno
  ===================================
     15       D8       SS   |   D10
     13       D7      MOSI  |   D11
     12       D6      MISO  |   D12
     14       D5      SCK   |   D13

    Note: If the ESP is booting at a moment when the SPI Master has the Select line HIGH (deselected)
    the ESP8266 WILL FAIL to boot!
    See SPISlave_SafeMaster example for possible workaround

*/

#include "SPISlave.h"
uint8_t* _Source = (const uint8_t*)(const void*)&SPIB;
void setup()
{
    Serial.begin(115200);
    Serial.setDebugOutput(true);

    // data has been received from the master. Beware that len is always 32
    // and the buffer is autofilled with zeroes if data is less than 32 bytes long
    // It's up to the user to implement protocol for handling data length
    SPISlave.onData([](uint8_t * _Source, size_t len) {
        SPISlave.setData(_Source);
        Serial.printf("Question: %s\n", (char *)_Source);
    });

    // The master has read out outgoing data buffer
    // that buffer can be set with SPISlave.setData
    SPISlave.onDataSent([]() {
        Serial.println("Answer Sent");
    });

    // status has been received from the master.
    // The status register is a special register that bot the slave and the master can write to and read from.
    // Can be used to exchange small data or status information
    SPISlave.onStatus([](uint32_t data) {
        Serial.printf("Status: %u\n", data);
        SPISlave.setStatus(millis()); //set next status
    });

    // The master has read the status register
    SPISlave.onStatusSent([]() {
        Serial.println("Status Sent");
    });

    // Setup SPI Slave registers and pins
    SPISlave.begin();

    // Set the status register (if the master reads it, it will read this value)
    SPISlave.setStatus(millis());

    // Sets the data registers. Limited to 32 bytes at a time.
    // SPISlave.setData(uint8_t * data, size_t len); is also available with the same limitation
    SPISlave.setData("Ask me a question!");
}

void loop() {}

Thanks in advance
Z

Arduino uses C++. So there is nothing specifically "Arduino" about your question.

I don't see where you are calling your function.

[quote author=Nick Gammon date=1479796246 link=msg=3010912]
Arduino uses C++. So there is nothing specifically "Arduino" about your question.

I don't see where you are calling your function.[/quote]
except I can't get figure out how to get the "calling" thing to work lol I have tried using other C++ code examples that are out there and should work but nothing complies when i try to use it in the arduino environment. Please give me the clue I am missing. How to call a lambda/anonymous function that will compile in the arduino environment. I rarely have this type of struggle I can usually figure it out but this is eluding me :o

See this C++11 - Lambda Closures, the Definitive Guide - Cprogramming.com

You are making a lambda function but you aren't calling it.

This is nothing to do with "the arduino environment". It is C++11 stuff.

[quote author=Nick Gammon date=1479797965 link=msg=3010937]
See this C++11 - Lambda Closures, the Definitive Guide - Cprogramming.com
You are making a lambda function but you aren't calling it.
This is nothing to do with "the arduino environment". It is C++11 stuff.[/quote]
Thank you! I was at whits end. I understand that its not specifically Arduino, but I have not found anything that works with arduino that isn't extremely complex or completely undocumented and confusing. Thank you for this link I greatly appreciate the help. I will attempt to create a simple example that works with arduino Uno, Document it well and post it for others to discover.
Z

It seems very weird to use lambda functions in the way you are attempting, but to show the idea here is your code reworked so the function is called:

void setup() {
  Serial.begin(115200);
  Serial.println("Starting.");
}
void loop() {
  [](int a)  {   Serial.print(a);   }  (5);
  //                                   ^^^  call the function supplying the argument 5
  Serial.println(".");
  delay(100);
}

That prints "5." repeatedly.

Or, if you are trying to capture a variable (a) - that is, make a closure - then you can do it like this:

void setup() {
  Serial.begin(115200);
  Serial.println("Starting.");
}
void loop() {
  int a = 42;
  [a]()  {   Serial.print(a);   }  ();
  Serial.println(".");
  delay(100);
}

Now "a" is not an argument to the lambda, it pulls it in from the local variable declared earlier. (It is a capture, not an argument).


Or, you can copy in any referenced external variables (not just "a") like this:

void setup() {
  Serial.begin(115200);
  Serial.println("Starting.");
}
void loop() {
  int a = 42;
  [=]()  {  Serial.print(a); }  ();
  Serial.println(".");
  delay(100);
}

Or pass them in by reference, which means you can change the variable:

void setup() {
  Serial.begin(115200);
  Serial.println("Starting.");
}
void loop() {
  static int a = 1;
  [&]()  {  Serial.print(a++); }  ();
  Serial.println(".");
  delay(100);
}

That prints:

Starting.
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
...
1 Like

A lambda might be more usefully used where you want an inline function such as a callback. For example, to sort some numbers:

const int COUNT = 10;

int someNumbers [COUNT] = { 7342, 54, 21, 42, 18, -5, 30, 998, 999, 3  };

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  // sort using inline compare function
  qsort (someNumbers, COUNT, sizeof (int), 
        // inline lambda to do comparisons
        [] (const void * arg1, const void * arg2)
        {
        int * a = (int *) arg1;  // cast to pointers to int
        int * b = (int *) arg2;
      
        // a less than b? 
        if (*a < *b)
          return -1;
          
        // a greater than b?
        if (*a > *b)
          return 1;
          
        // must be equal
        return 0;
        }  // end of lambda function
        );
  for (int i = 0; i < COUNT; i++)
    Serial.println (someNumbers [i]);
  }  // end of setup

void loop () { }

Is there a good use for such a function, other than to make it even harder for someone else to figure out what the code does?

Read this - basically it lets you set up a function with a "closure" - that is, when it is closed it gets a copy of an external variable. They do have their uses.

I have to agree; the syntax looks strained.
The "[]" seems to set you up for some sort of array.
Then it all turns to poo.

AWOL:
I have to agree; the syntax looks strained.
The "[]" seems to set you up for some sort of array.
Then it all turns to poo.

Not going to dispute the syntax issue, but in desktop C++ programs anonymous functions work great with STL algorithms. If you're using something like find_if with a predicate you only use once at that point, instead of making a named function somewhere else that you need to hunt down you can inline it with a lambda like Nick showed with qsort.

Without a port of std::function though I imagine it's of very limited usefulness.

This is wonderful! Thank you Nick Gammon, Jiggy-Ninja and AWOL for your contribution to my understanding. Especially you Nick Gammon having code that actually compiles and works has given me an understanding I was lacking.

now my question is how to create a function that I can use Lambda in like SPISlave does :

void setup()
{ 
 // status has been received from the master.
  // The status register is a special register that bot the slave and the master can write to and read from.
  // Can be used to exchange small data or status information
  SPISlave.onStatus(
    // inline lambda
    [](uint32_t data) {
       Serial.printf("Status: %u\n", data);
       SPISlave.setStatus(data); //set next status
    }  // end of lambda function
  );
}

The class function SPISlave.onStatus() is this accepting a callback function?
SPISlave library

in the .h file
typedef std::function<void(uint32_t status)> SpiSlaveStatusHandler;
...
    SpiSlaveStatusHandler _status_cb;
------------------------------------------------------------------------
int the .cpp file
void SPISlaveClass::onStatus(SpiSlaveStatusHandler cb)
{
    _status_cb = cb;
}

void SPISlaveClass::_status_rx(uint32_t data)
{
    if(_status_cb) {
        _status_cb(data);
    }
}

As I see this, the lambda function is created as an anonymous lambda function and then stored in _status_cb or at least a pointer to it. now later on this can be ran when the _status_rx() is triggered and data is passed to the lambda function.

Wow.. am I close? :slight_smile:

Had another idea :o :
attachInterrupt() can accept lambda function as its second argument!!! I Get how to do this!!! Thank you!

#define interruptPin 2
volatile unsigned long timeX = 1;
volatile unsigned long LastTime;
volatile int PulseCtrX;

void setup() {

  attachInterrupt(digitalPinToInterrupt(interruptPin), 
    // inline lambda
    []() {
       unsigned long Time;
       Time = micros();
       timeX = (Time - LastTime); // this time is accumulative between readings
       LastTime = Time;
       PulseCtrX ++; // will usually be 1 unless something else delays the use of hte sample
    }  // end of lambda function
    , FALLING); // end of attachInterrupt()

}

void loop() {
// Other code to handle tachometer input
}

Z

Uno compatible lambda called by pointer

typedef void (*voidFuncPtr)(void);
static volatile voidFuncPtr  _status_cb[1];
void SetCallback(volatile voidFuncPtr cb){
  _status_cb[0] = cb;
}
void TriggerCallback(){
  if (_status_cb[0]) {
    _status_cb[0]();
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("Start");
  SetCallback([]() {
    Serial.print("Callback");
  });
}

void loop() {
  TriggerCallback();
  Serial.println(".");
  delay(1000);
}

Lambda Blink without Delay!!! with Call Back example!

typedef void (*voidFuncPtr)(void);// Create a type to point to a function.
static volatile voidFuncPtr  _CallBackFunctionPointer; // Create an instance of the empty function pointer
void BlinkIt(volatile voidFuncPtr CallBackFunctionPointer) {
  _CallBackFunctionPointer= CallBackFunctionPointer; // assign a function to the empty function pointer
}
void Blink(unsigned long msDelaTime) {
  if (CallBackFunctionPointer) {
    static unsigned long _ATimer;
    if ( (unsigned long)(millis() - _ATimer) >= (msDelaTime)) {
      _ATimer = millis();
      _CallBackFunctionPointer(); // call the function we assigned to the once empty function pointer
    }
  }
}
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  BlinkIt(// BlinkIt takes a function for an Input we are going to use a lambda function
    // Lambda function Starting here
    []() {
      digitalWrite(13, !digitalRead(13));
    } // Lambda function ends here
  ); // end of BlinkIt function
}

void loop() {
  Blink(1000);
}

Help me correct my terminology. I am self taught Except for 1 C programming class back in 1992 :slight_smile:

zhomeslice:
Uno compatible lambda called by pointer

typedef void (*voidFuncPtr)(void);

static volatile voidFuncPtr  _status_cb[1];
void SetCallback(volatile voidFuncPtr cb){
  _status_cb[0] = cb;
}
void TriggerCallback(){
  if (_status_cb[0]) {
    _status_cb0;
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("Start");
  SetCallback( {
    Serial.print("Callback");
  });
}

void loop() {
  TriggerCallback();
  Serial.println(".");
  delay(1000);
}

That is awsome. I could have sworn I had trouble using lambdas with a function pointer before and I couldn't get it to work. That you for posting something that works.

zhomeslice:

typedef void (*voidFuncPtr)(void);// Create a type to point to a funciton.

static volatile voidFuncPtr  _CallBackFuncitonPointer; // Create an instance of the empty function pointer
...
}




Help me correct my terminology. I am self taught Except for 1 C programming class back in 1992 :)

It's a function, not a funciton!

Thanks for the catch. Corrected all of them. Cut and paste and typing too fast lol :slight_smile: