I hate to be so dumb, but how do I read this? Syntax question

ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });

what does the ( do? I mean, I get that there are braces and curly braces between the parentheses but what is going on?

Well, that's two of us that are equally dumb! I have no idea what that means.

1 Like

Lambda expression as a parameter.

https://en.cppreference.com/w/cpp/language/lambda

Nothing quite like clear, clean, easily understandable programming!

1 Like

A function with no name, that takes no parameters

So I've read the Wikipedia article, and I still have no idea what it is or what it's for. That's fine - I'm old now and don't need to understand it.

2 Likes

For things like here, where you need a callback, but you don't have to / want to give the function a name

2 Likes

I can't stop laughing enough to type this nearly

ok I'll bite, what's a "callback"?

A function that you provide to a subsystem to be called at a later time, in response to an event, like here, the event being the end of OTA update.

You have the library source - why not go exploring?

Note, this function happens not to take parameters, but others like OTA progress may well do.

I don't know if I've ever run across a case where you had to use a lambda and a named function wouldn't work. I'll supply the named function almost every time, even if it's only used once. Perhaps lambdas provide a performance advantage in certain situations? If so, bet it's minor in cases I've come across. I think using a named function is clearer. Also, the lambda syntax is ugly.

I'm with you on this one.

I don't disagree that the syntax is ugly, but they are useful, if only for the reason that I don't have to think up a name (I used to have real problems thinking of names for the intermediate dimensions of multi-dimensional arrays in COBOL. You weren't there, man)

Consider this example (before this thread turns into a meaningless beauty contest for programming language syntax):

Timer timer;

void setup() {
  Serial.begin(115200);
  Serial.println("Start");
  timer.setTimeout([] { Serial.println("Callback called"); },
                   2000);
}

void loop() {
  timer.update();
}

Where the Timer class could be implemented as follows:

#include <functional> // std::function

class Timer {
  public:
    Timer() = default;

    void setTimeout(std::function<void()> callback, unsigned long duration) {
      this->callback = std::move(callback); // save the function to be called when the timeout expires
      this->startTime = millis();           // record the current time
      this->duration = duration;            // save the duration to wait before calling the callback
    }

    void update() {
      if (callback && millis() - startTime >= duration) {
        callback();    // call the callback function
        callback = {}; // remove the callback function
      }
    }

  private:
    std::function<void()> callback;
    unsigned long startTime;
    unsigned long duration;
};

This will print “Start” and then 2 seconds later it will print “Callback called”.

In this case, you could write a free function to do the same thing, i.e.

void whatToDoWhenTheTimeoutFires() {
  Serial.println("Callback called");
}

void setup() {
  Serial.begin(115200);
  Serial.println("Start");
  timer.setTimeout(whatToDoWhenTheTimeoutFires,
                   2000);
}

but for such a short function, that is unnecessarily verbose, and increases the cognitive load because the reader of the code has to go look up and jump to the implementation of that function to see what's going on. Lambda's keep this local, and I'd argue that inventing a name for a function that is used only once and that just prints a string to the serial port is rather pointless.
For a one-line function call, the lambda syntax is nice and concise.

Another advantage of lambda's is that they can capture variables from the current scope, which is impossible for normal free functions:

void setup() {
  Serial.begin(115200);
  Serial.println("Start");
  const char *message = "Callback called";
  timer.setTimeout([=] { Serial.println(message); },
                   2000);
}
2 Likes

I agree, what is wrong with naming all your functions. Holy smokes, this stuff is confusing enough already. although maybe ArduinoOTA.onEnd is the name of the function and something somewhere gets triggered to come here and continue processing at this address. until that's done when it goes back to where it came from.

No, "onEnd" is simply an accessor function (a putter, not a getter)

COBOL :face_vomiting:. I was there! :laughing:

When do the flashbacks end?
It's over forty years now.

I sure was. Even got to meet the inventor Grace Hopper.

I thought members of the armed forces were bound by the terms of the Hague and Geneva Conventions?