IDE bug or feature? (function with default arguments)

Normally it does not matter in which order the functions are declared.
Usually one can declare a function after loop(), but use it inside loop().

But if the function contains arguments with default values, they must be declared strictly before they are called, otherwise there is a compilation error: ’ was not declared in this scope’
Tested with IDE 1.8.8, IDE 1.6.5 for Arduino Uno

Here is an example based on ‘blink’
this will not compile:

<setup()> is here
.......
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
  test(5);
}

void test(int n1, boolean b1=false) {
  delay(10);
}

but this will compile:

void test(int n1, boolean b1=false) {
  delay(10);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
  test(5);
}

and this will compile as well:

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
  test(5);
}

void test(int n1) {
  delay(10);
}

bool ?

The Arduino IDE normally generates function prototypes for any function in a .ino file that doesn’t already have one in your code. This allows you to call functions in the code before they have been defined without adding the extra complication of learning to write function prototypes to the beginner’s learning curve.

However, this is not done for function definitions which contain default parameter values. The reason for this is that it would be fairly complex and invasive to do it correctly. Here’s a minimal example:

void setup() {
  foo();
}

void foo(byte bar = 42) {}

void loop() {}

Normally, after the Arduino IDE did its sketch preprocessing to turn it into valid C++, it would look like this:

#include <Arduino.h>
#line 1 "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_modified_sketch_387682\\DefaultParam.ino"
#line 1 "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_modified_sketch_387682\\DefaultParam.ino"
#line 1 "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_modified_sketch_387682\\DefaultParam.ino"
void setup();
#line 5 "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_modified_sketch_387682\\DefaultParam.ino"
void foo(byte bar = 42);
#line 7 "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_modified_sketch_387682\\DefaultParam.ino"
void loop();
#line 1 "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_modified_sketch_387682\\DefaultParam.ino"
void setup() {
  foo();
}

void foo(byte bar = 42) {}

void loop() {}

But that code would not compile:

DefaultParam:7:23: error: default argument given for parameter 1 of 'void foo(byte)' [-fpermissive]

 void foo(byte bar = 42) {}

                       ^

E:\electronics\arduino\temp\DefaultParam\DefaultParam.ino:1:6: note: previous specification in 'void foo(byte)' here

 void foo(byte bar = 42);

      ^~~

In order to generate a function prototype where there was a default parameter in the function definition, the preprocessor would need to also remove the default parameter from the function definition. That could be quite tricky to do reliably, and people might object to the preprocessor messing with the code they wrote in addition to added code (which some people already complain about).

The solution is to write your own function prototypes for functions with default parameters.

When sketch preprocessing does something unexpected, it can be very confusing since the problem is with invisible code (or in this case, the lack thereof). When you encounter such a problem, it can be very helpful to examine the post-sketch preprocessing output:

  • File > Preferences
  • Check the box next to "Show verbose output during: compilation’
  • Click “OK”
  • Sketch > Verify/Compile
  • After compilation fails, scroll the black console window at the bottom of the Arduino IDE window all the way to the top.
  • Examine the first line of output to find the value of the “-build-path” option.

For example, if you had this:

C:\ArduinoIDE\arduino-nightly\arduino-builder -dump-prefs -logger=machine -hardware C:\ArduinoIDE\arduino-nightly\hardware -hardware C:\Users\per\AppData\Local\Arduino15\packages -hardware E:\electronics\arduino\hardware -tools C:\ArduinoIDE\arduino-nightly\tools-builder -tools C:\ArduinoIDE\arduino-nightly\hardware\tools\avr -tools C:\Users\per\AppData\Local\Arduino15\packages -built-in-libraries C:\ArduinoIDE\arduino-nightly\libraries -libraries E:\electronics\arduino\libraries -fqbn=esp32:esp32:node32s:FlashFreq=80,UploadSpeed=921600 -vid-pid=0X2341_0X0042 -ide-version=10809 -build-path C:\Users\per\AppData\Local\Temp\arduino_build_889992 -warnings=all -build-cache C:\Users\per\AppData\Local\Temp\arduino_cache_764477 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.esptool.path=C:\Users\per\AppData\Local\Arduino15\packages\esp32\tools\esptool\2.3.1 -prefs=runtime.tools.esptool-2.3.1.path=C:\Users\per\AppData\Local\Arduino15\packages\esp32\tools\esptool\2.3.1 -prefs=runtime.tools.mkspiffs.path=C:\Users\per\AppData\Local\Arduino15\packages\esp32\tools\mkspiffs\0.2.3 -prefs=runtime.tools.mkspiffs-0.2.3.path=C:\Users\per\AppData\Local\Arduino15\packages\esp32\tools\mkspiffs\0.2.3 -prefs=runtime.tools.xtensa-esp32-elf-gcc.path=C:\Users\per\AppData\Local\Arduino15\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-80-g6c4433a-5.2.0 -prefs=runtime.tools.xtensa-esp32-elf-gcc-1.22.0-80-g6c4433a-5.2.0.path=C:\Users\per\AppData\Local\Arduino15\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-80-g6c4433a-5.2.0 -verbose C:\Users\per\AppData\Local\Temp\arduino_modified_sketch_19197\sketch_dec31a.ino

the temporary build folder is C:\Users\per\AppData\Local\Temp\arduino_build_889992.

Open the .ino.cpp file in the sketch subfolder of the temporary build folder with a text editor.

The temporary build folder will be deleted when you exit the Arduino IDE.

hammy:
bool ?

boolean is a type alias for bool Arduino defines in the core library. I think they did this because in the very early days (perhaps before Arduino was even created and there was only the Wiring project), the assumption was that the users would already be writing Processing code for their computer, and that it would be more approachable if they could write very similar code to run on microcontrollers. The Wiring/Arduino IDE was even based on the Processing IDE so the interface was familiar. Now, there turned out to be not really such a strong intersection between the Processing and Arduino world and I think any advantages of using the boolean type are far outweighed by the fact that it is moving the user farther away from writing standardized C++ code. So I recommend using bool, but the boolean type will work fine as long as the code contains an #include directive for Arduino.h (which is done automatically for .ino files).

pert:
boolean is a type alias for bool Arduino defines in the core library.

learn something new every day :slight_smile: