Need help understanding a typedef [SOLVED]

In this sketch, which is based on the FastLED "100-lines-of-code" demo reel, there is a typedef between the setup() and loop() functions.
If I move this code block to before the setup, I get this error:

'rainbow' was not declared in this scope

But when the block is between the setup and loop functions, it compiles and runs just fine.

Why??

All of the functions not in scope are defined below the loop function So, what difference does it make to the precompiler where the typedef appears?

#define SKETCH "XmasTree2_OTA.ino"

#include <FastLED.h>
#include "ESP8266WiFi.h"
#include "D:\River Documents\Arduino\libraries\Kaywinnet.h"
#include <ArduinoOTA.h>

FASTLED_USING_NAMESPACE

// Inspired by
// FastLED "100-lines-of-code" demo reel, showing just a few
// of the kinds of animation patterns you can quickly and easily
// compose using FastLED.
//
// This example also shows one easy way to define multiple
// animations patterns and have them automatically rotate.
//
// -Mark Kriegsman, December 2014

#if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000)
#warning "Requires FastLED 3.1 or later; check github for latest code."
#endif


/*
   This is the sketch finally used on the Christmas Tree with a topper LED.
   The topper LED is on pin D1.
*/

#define TOP_PIN D1
#define DATA_PIN D2
#define LED_TYPE WS2811
#define COLOR_ORDER RGB
#define NUM_LEDS 50

CRGB leds[NUM_LEDS];
CRGB top[1];                // Tree topper, one LED

#define BRIGHTNESS          50
#define FRAMES_PER_SECOND  120


uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current
uint8_t gHue = 0; // rotating "base color" used by many of the patterns




// --------------------------- setup ---------------------------
void setup() {
  delay(1000);    // No one knows why.

  setup_wifi();
  start_OTA();

  FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.addLeds<LED_TYPE, TOP_PIN, COLOR_ORDER>(top, 1).setCorrection(TypicalLEDStrip);

  FastLED.setBrightness(BRIGHTNESS);

  // Init the topper
  top[0] = CRGB::Yellow;
  FastLED.show();
}


// ------------- List of patterns -------------
// List of patterns to cycle through.  Each is defined as a separate function below.
typedef void (*SimplePatternList[])();
// Removed confetti and sinelon from the original sample.
SimplePatternList gPatterns = { rainbow, rainbowWithGlitter, juggle, bpm };



// --------------------------- loop ---------------------------
void loop() {
  ArduinoOTA.handle();

  // Call the current pattern function once, updating the 'leds' array
  gPatterns[gCurrentPatternNumber]();

  FastLED.show();
  FastLED.delay(1000 / FRAMES_PER_SECOND);

  EVERY_N_MILLISECONDS( 20 ) {
    gHue++;  // slowly cycle the "base color" through the rainbow
  }

  EVERY_N_SECONDS( 10 ) {
    nextPattern();  // change patterns periodically
  }
}




// ------------- nextPattern -------------
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
void nextPattern()
{
  // add one to the current pattern number, and wrap around at the end
  gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE( gPatterns);
}


// ------------- Rainbow -------------
void rainbow()
{
  // FastLED's built-in rainbow generator
  fill_rainbow( leds, NUM_LEDS, gHue, 7);
}


//------------- Rainbow with glitter -------------
void rainbowWithGlitter()
{
  // built-in FastLED rainbow, plus some random sparkly glitter
  rainbow();
  addGlitter(80);
}


//------------- addGlitter -------------
void addGlitter( fract8 chanceOfGlitter)
{
  if ( random8() < chanceOfGlitter) {
    leds[ random16(NUM_LEDS) ] += CRGB::White;
  }
}


//------------- confetti -------------
void confetti()
{
  // random colored speckles that blink in and fade smoothly
  fadeToBlackBy( leds, NUM_LEDS, 10);
  int pos = random16(NUM_LEDS);
  leds[pos] += CHSV( gHue + random8(64), 200, 255);
}


//------------- sinelon -------------
void sinelon()
{
  // a colored dot sweeping back and forth, with fading trails
  fadeToBlackBy( leds, NUM_LEDS, 20);
  int pos = beatsin16( 13, 0, NUM_LEDS - 1 );
  leds[pos] += CHSV( gHue, 255, 192);
}


//------------- bpm -------------
void bpm()
{
  // colored stripes pulsing at a defined Beats-Per-Minute (BPM)
  uint8_t BeatsPerMinute = 62;
  CRGBPalette16 palette = PartyColors_p;
  uint8_t beat = beatsin8( BeatsPerMinute, 64, 255);
  for ( int i = 0; i < NUM_LEDS; i++) { //9948
    leds[i] = ColorFromPalette(palette, gHue + (i * 2), beat - gHue + (i * 10));
  }
}


//------------- juggle -------------
void juggle() {
  // eight colored dots, weaving in and out of sync with each other
  fadeToBlackBy( leds, NUM_LEDS, 20);
  byte dothue = 0;
  for ( int i = 0; i < 8; i++) {
    leds[beatsin16( i + 7, 0, NUM_LEDS - 1 )] |= CHSV(dothue, 200, 255);
    dothue += 32;
  }
}

Perhaps it's related to Arduino's auto function prototype generation. Try supplying them explicitly. I'm not on computer now, so can't try it.

gfvalvo:
Perhaps it's related to Arduino's auto prototype generation. Try supplying them explicitly. I'm not on computer now, so can't try it.

Correct. If you list the prototypes for those functions explicitly it will compile. The other alternative is to leave the .ino empty and use another .cpp file but in that case you will have include the prototypes anyhow or define the functions before the typedef and array definition.

I thought I'd expand on the explanation already given to make sure it's clear.

In order to make things more simple for beginners, the Arduino IDE automatically generates function prototypes for any function in a .ino that doesn't already have a prototype. It turns out that this is pretty tricky to do right because the function prototypes have to be inserted into the code in just the right place. The Arduino developers have continually improved on the prototype generation system to the point where it only gets it wrong in very rare cases (such as the one you discovered). But when it does get it wrong, it can be very confusing because then you have an error caused by a bug in automatically generated code that doesn't even exist in your sketch!

Here's a minimal demonstration:

typedef void (*functionList[])();
functionList myFunctions = {foo};
void setup() {}
void loop() {}
void foo() {}

Compiling this with Arduino IDE 1.8.10 (note that the prototype generation behavior may change from one IDE version to another due to continued development) results in the error:

Foo:2:29: error: 'foo' was not declared in this scope

 functionList myFunctions = {foo};

                             ^~~

If you turn on File > Preferences > Show verbose output during > compilation, and then check the console output after compilation, you can find the location of the preprocessed sketch file with the automatically generated function prototypes. It's the .ino.cpp file in the sketch subfolder of the temporary build folder. Here's the last couple lines of my output:

Compiling sketch...
"C:\\Users\\per\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino5/bin/avr-g++" -c -g -Os -Wall -Wextra -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10810 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\\Users\\per\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.2\\cores\\arduino" "-IC:\\Users\\per\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.2\\variants\\standard" "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_build_51144\\sketch\\Foo.ino.cpp" -o "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_build_51144\\sketch\\Foo.ino.cpp.o"

So I can see that my preprocessed file is at C:\Users\per\AppData\Local\Temp\arduino_build_51144\sketch\Foo.ino.cpp
The contents of that file are:

#include <Arduino.h>
#line 1 "E:\\electronics\\arduino\\Foo\\Foo.ino"
typedef void (*functionList[])();
functionList myFunctions = {foo};
#line 3 "E:\\electronics\\arduino\\Foo\\Foo.ino"
void setup();
#line 4 "E:\\electronics\\arduino\\Foo\\Foo.ino"
void loop();
#line 5 "E:\\electronics\\arduino\\Foo\\Foo.ino"
void foo();
#line 3 "E:\\electronics\\arduino\\Foo\\Foo.ino"
void setup() {}
void loop() {}
void foo() {}

You can see the sketch preprocessor has added function prototypes for setup, loop, foo. It has also added the #include directive for Arduino.h, which provides the declarations of the Arduino core library functions.

In C++, you must declare a function before the first place it is referenced in the code. You could accomplish that by defining the function, but that forces a given organization of the code that might be inconvenient, or maybe even impossible. So the alternative is to write function prototypes that just tell the compiler the signature of the function, which is all it needs. The problem with the above code is that the preprocessor has inserted the prototype for foo() after it was referenced in the initialization of myFunctions, thus the error.

Now we can consider this minimal demonstration sketch:

#include <Arduino.h>
#line 1 "E:\\electronics\\arduino\\Foo\\Foo.ino"
typedef void (*functionList[])();
#line 2 "E:\\electronics\\arduino\\Foo\\Foo.ino"
void setup();
#line 4 "E:\\electronics\\arduino\\Foo\\Foo.ino"
void loop();
#line 5 "E:\\electronics\\arduino\\Foo\\Foo.ino"
void foo();
#line 2 "E:\\electronics\\arduino\\Foo\\Foo.ino"
void setup() {}
functionList myFunctions = {foo};
void loop() {}
void foo() {}

Now you can see that putting the declaration of myFunctions after the definition of setup() happens to have caused the Arduino IDE to put the foo prototype in the right place. But maybe you don't want to organize your code that way. The alternative is to manually add a function prototype for foo() so that you are sure it will be in the right place:

void foo(); // function prototype
typedef void (*functionList[])();
functionList myFunctions = {foo};
void setup() {}
void loop() {}
void foo() {}

Thanks for all the detailed responses. As usual you pointed me to the solution. It was not the typedef that needed to be prototyped, it was the functions named in the SimplePatternList array:

Adding this above the setup() function fixed the issue:

void rainbow();
void rainbowWithGlitter();
void bpm();
void juggle();

typedef void (*SimplePatternList[])();
SimplePatternList gPatterns = { rainbow, rainbowWithGlitter, juggle, bpm };