how does this work for (const auto& sym : kTickerSymbol) {

I found this in some GitHub code and really do not understand whats going on. you have const auto being filled with the value from &sym, so is that just saying do the loop as many times as that value? I’ve never seen a for loop like this. Can anyone explain how this works?

for (const auto& sym : kTickerSymbol) {
      Price       = doc[sym]["quote"]["latestPrice"].as<String>();
      CompanyName[0] = doc[sym]["quote"]["companyName"].as<String>();
      Change      = doc[sym]["quote"]["change"].as<String>();
      F2WeekHi    = doc[sym]["quote"]["week52High"].as<String>();
      F2WeekLo    = doc[sym]["quote"]["week52Low"].as<String>();
      MarCap      = doc[sym]["quote"]["marketCap"].as<String>();
      PE          = doc[sym]["quote"]["peRatio"].as<String>();
      auto change_percent = doc[sym]["quote"]["changePercent"].as<String>();
      auto as_of_date = doc[sym]["quote"]["latestTime"].as<String>();
      auto msg2 = CompanyName[0]  + " " + sym  + ":" + Price  + ", " + Change  + " (" + MarCap  + ") as of " + as_of_date + "  " + PE ;
      Serial.print("msg2="); Serial.println(msg2);
      StocksDone += 1;
      if (StocksDone < 3) {
        YouDidItAlready = true;
      }
      Serial.print("CompanyName= "); Serial.println(CompanyName[0]);
    }

Google for C++ range-based for loop.

const = immutable
auto = let the compiler infer the data type
& = by reference (rather than making a copy)
sym = the identifier of the current element in the collection you're iterating over
: = "in", part of the syntax of a range-based for loop
kTickerSymbol = the collection being iterated over

A simple example:

String array[] = {"one", "two", "three"};
for (String element : array) { // for each element in the array, making a copy
  Serial.println(element);
}

Let's say that you don't care what the type of the element is, then you can use the "auto" keyword to let the compiler infer the type for you:

for (auto element : array) { // for each element in the array, making a copy
  Serial.println(element);
}

On each iteration, you're making a copy of the current element. Making copies of a String is expensive, so you might want to use a reference instead. The reference refers to the String in the array directly, instead of allocating a new String and copying the contents.

for (auto &element : array) { // for each element in the array, by mutable reference
  Serial.println(element);
}

If you don't want to change the element inside of the loop, it's good practice to use an immutable reference:

for (const auto &element : array) { // for each element in the array, by immutable reference
  Serial.println(element);
}

Pieter

Thanks. I really didn't know there were modifications like that on the basic for loop. That's actually pretty handy you don't even have to tell it how many items are in the tray or the size. I have been fooling with this stuff for 4 years and this is the first I have seen it.

Just to confirm, by adding & to the name of the array item you prevent the array from being altered. Is that correct?

sevenoutpinball:
Just to confirm, by adding & to the name of the array item you prevent the array from being altered. Is that correct?

No, the & declares "element" as a reference. You can use this reference to alter the array. If you don't want alter the array, either copy the element, or use a const reference.

Try the following:

void setup() {
  Serial.begin(115200);
  while(!Serial);

  { // First version: by value, creating a copy
    String array[] = { "one", "two", "three" };
    for (auto element : array)
      element = "altered"; // "element" is a copy of the String in the array, this statement only alters the copy, not the actual array
    for (auto element : array)
      Serial.println(element);
  }

  Serial.println("---");

  { // Second version: by reference
    String array[] = { "one", "two", "three" };
    for (auto &element : array)
      element = "altered"; // "element" is a reference to the String in the array, this statement alters the array
    for (auto element : array)
      Serial.println(element);
  }
}

void loop() {}

The output is:

one
two
three
---
altered
altered
altered

The third option is to use a const reference, it refers to the element in the array without creating a copy, but you cannot use the reference to alter the array, if you try it anyway you (should) get a compilation error:

  { // Third version: by immutable reference
    String array[] = { "one", "two", "three" };
    for (const auto &element : array)
      element = "altered"; // compile-time error:
      // error: passing 'const String' as 'this' argument discards qualifiers
      // You cannot assign anyting to the element, because it is a read-only reference.
    for (auto element : array)
      Serial.println(element);
  }

(Note: the Arduino IDE uses the -fpermissive flag to compile your sketches, and it will compile the third version with just a warning. That doesn't change the fact that it's wrong, your code is invalid, even though the Arduino IDE ignores the error.
Turning on the -fpermissive was a huge mistake by the Arduino developers in my opinion, but it's almost impossible to revert, because that would cause many existing sketches to fail to compile.)

Ok, I ran your code, to sum up then, "" for (auto element : array) ""creates a copy called element? so now there are two arrays. or maybe not two arrays, just that the original one was copied from.

and ""for (auto &element : array)"" is using the original array. The word reference is somewhat ambiguous I think.

Some of this stuff is downright exotic.

I wondered what -fpermissive meant. I usually go thru looking for all the warnings. Most tend to be in other software from people that get paid to do this so I don't understand that. And sometimes I see warnings from other stuff, I change what I am doing and the warnings go away. I don't understand that either.

Thanks for your time and help!!

So adding const in your for loop prevents changes in the array. So yeah, it's constant in this instance because it's a copy, but the original may or may not be a constant.

sevenoutpinball:
Ok, I ran your code, to sum up then, “” for (auto element : array) ""creates a copy called element? so now there are two arrays. or maybe not two arrays, just that the original one was copied from.

It creates a copy of each element, not of the array. There is only one copy alive at any given moment.

Think of it like this:

for (size_t i = 0; i < 3; ++i) {
  String element = array[i]; // create a copy the i-th element
  element = "altered";
}

sevenoutpinball:
and ““for (auto &element : array)”” is using the original array. The word reference is somewhat ambiguous I think.

Reference is not ambiguous, it has a precise meaning in the context of C++: Reference initialization - cppreference.com

sevenoutpinball:
And sometimes I see warnings from other stuff, I change what I am doing and the warnings go away. I don’t understand that either.

I’m not sure what you mean?

sevenoutpinball:
So adding const in your for loop prevents changes in the array.

Yes.

sevenoutpinball:
So yeah, it’s constant in this instance because it’s a copy, but the original may or may not be a constant.

When using references, you don’t make a copy, you refer to the original element in the array.

const does not mean “constant” in the usual sense, it makes the reference read-only. You can have multiple references that refer to the same object, some can be read-only (const), while others can be used to alter the original object.

String str = "abc";
String &ref1 = str; // mutable reference
const String &ref2 = str; // immutable/read-only reference

ref1 = "def"; // ref1 can be used to alter str
Serial.println(ref2); // ref2 can only be used to read str

I’m not sure what you mean?

Well here are errors that in some cases don’t show up. Maybe the compiler only checks code that is going to be used. Is it ok to just fix these errors in the .cpp files?

In file included from /Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.cpp:12:0:
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h:727:6: warning: unused parameter 'channelNumber' [-Wunused-parameter]
  int writeFields(unsigned long channelNumber, const char * writeAPIKey)
      ^
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h:902:6: warning: unused parameter 'channelNumber' [-Wunused-parameter]
  int writeRaw(unsigned long channelNumber, String postMessage, const char * writeAPIKey)
      ^
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h: In member function 'int ThingSpeakClass::getHTTPResponse(String&)':
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h:1563:18: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    if(millis() > timeoutTime){
                  ^
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h:1613:18: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    if(millis() > timeoutTime){
                  ^

sevenoutpinball:
Well here are errors that in some cases don't show up. Maybe the compiler only checks code that is going to be used.

Yes, it depends on whether the code is used, whether it's inlined, what optimization level you're at, etc.

sevenoutpinball:
Is it ok to just fix these errors in the .cpp files?

In file included from /Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.cpp:12:0:

/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h:727:6: warning: unused parameter 'channelNumber' [-Wunused-parameter]
  int writeFields(unsigned long channelNumber, const char * writeAPIKey)
      ^
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h:902:6: warning: unused parameter 'channelNumber' [-Wunused-parameter]
  int writeRaw(unsigned long channelNumber, String postMessage, const char * writeAPIKey)
      ^
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h: In member function 'int ThingSpeakClass::getHTTPResponse(String&)':
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h:1563:18: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    if(millis() > timeoutTime){
                  ^
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h:1613:18: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    if(millis() > timeoutTime){
                  ^

It looks like the channelNumber parameter is only used when debugging prints are enabled. It seems weird that they don't use it for the actual writing, so it might be a bug, but I'm not familiar with ThingSpeak, so I don't know what its purpose would be.

The millis() > timeoutTime could be a more serious bug, though. In general, you should always use unsigned long to store anything related to millis(), and check the difference, rather than adding a timeout to the current time.

I use thingspeak (free so far) to log data and allow one device to read data from devices on other networks. I haven't yet figured out how to use an esp8266 to say read a camera in another location. One thing at a time. yes, obviously millis() is never going to be negative. And the unused variable is the place you are writing so I don't know how that is unused. but it works at least.

sevenoutpinball:
Well here are errors that in some cases don't show up. Maybe the compiler only checks code that is going to be used. Is it ok to just fix these errors in the .cpp files?

In file included from /Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.cpp:12:0:

/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h:727:6: warning: unused parameter 'channelNumber' [-Wunused-parameter]
  int writeFields(unsigned long channelNumber, const char * writeAPIKey)
      ^
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h:902:6: warning: unused parameter 'channelNumber' [-Wunused-parameter]
  int writeRaw(unsigned long channelNumber, String postMessage, const char * writeAPIKey)
      ^
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h: In member function 'int ThingSpeakClass::getHTTPResponse(String&)':
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h:1563:18: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    if(millis() > timeoutTime){
                  ^
/Users/billbe/LocalArduino/libraries/ThingSpeak/ThingSpeak.h:1613:18: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    if(millis() > timeoutTime){
                  ^

Just to be clear, those are warnings not errors. There is a difference