Why does replace() function not work before setup() function?

Hi all!

This is my first posing in this forum. I'm learning to handle Arduino or better the Arduino C/C++ language. Right now, I try to understand why I'm getting an error if I run a function outside another function.

If I write the following:

void setup() {
  String myString = "Hello World!\n";
  myString.replace("World", "Harry");

  Serial.begin(9600);
  Serial.print(myString);
}

void loop() {
}

The code compiles without an error.

If I write this:

String myString = "Hello World!\n";
myString.replace("World", "Harry");

void setup() {
  Serial.begin(9600);
  Serial.print(myString);
}

void loop() {
}

I get an error: "'myString' does not name a type"? Isn't "String" the type?

Why is there a difference in running the replace() function outside of the setup() function?

Thank you in advance! And I hope, this is not a stupid question! :-[

The reason is that code can only be executed within a function

OK, thank you!

Variables can be declared outside / before functions? And all other code will have to (or better must) be inside the setup() or loop() function to run? I didn't notice that... :cold_sweat:

Variables can be declared either outside of a function, in which case they will have global scope and be available throughout the program, or inside a function in which case they will have local scope and will only be available in the function. Running the function again will declare a new variable of the same name and its previous value will not be retained unless it is declared static

Ok, I think I understand the scope-concept. I think I'm too "newbie" to understand this fundamental OOP.

When I'm declaring a "StringObject" globally, why can't I use a "StringObject Function" on this globally declared Object globally? Why can I only use it in the scope of another function?

What I'm missing here? I don't see it. :confused: :cry:

works:

String myString = "Hello World!\n";
void setup() {
  Serial.begin(9600);
  Serial.print(myString);
  myString.replace("World", "Harry");
}

void loop() {
}

error:

String myString = "Hello World!\n";
myString.replace("World", "Harry");
void setup() {
  Serial.begin(9600);
  Serial.print(myString);
}

void loop() {
}

ReplaceError_String_sketch_feb01a:2:1: error: 'myString' does not name a type
myString.replace("World", "Harry");
^~~~~~~~
exit status 1
'myString' does not name a type

What I'm missing here? I don't see it

See reply#1

Ok, I read that. Variable declaration is also code in my opinion. But obviously, I can't do anything else than define constants, variables, and load headers.
Thanks a lot! :-*

Variable declaration is also code in my opinion

The language specification doesn’t care about your opinion.

:wink:
Do you know, where I can find the official "language specification" where this structure is explained?

henrynoh:
:wink:
Do you know, where I can find the official "language specification" where this structure is explained?

Google knows.

I think I'm too "newbie" to understand this fundamental OOP.

really scope and variable declaration / initial value has nothing to do with OOP... it's pretty standard in many language.

here is a link to C++ stuff

information on Scope
information on initialization

C and C++ are pretty ancient languages, with many quirks and oddities. The design dates back to the late 1970's I think.

J-M-L & MarkT
Thank you!

myString.replace("World", "Harry");

This is not a function declaration.
This is a call to the String class method.
C(++) is a procedural language. Code executes one line at a time, starting at

int main(void) {

found deep inside the ArduinoCore-avr, part of the magic behind Arduino, which calls setup() first and then loop() repeatedly indefinitely. Instantiating a String object happens outside of this procedure, and only exists in source code. You declare, instantiate, initialize myString with the line

String myString = "Hello World!\n";

You can do this "outside" setup() or loop() in which case it is a global object, residing in static RAM and having global scope. If you do this inside setup() or loop(), it is a local object, appearing on the stack in managed RAM for the duration of execution of that function, and having a local scope, meaning it can only be referenced inside that function. As a class of String, myString inherits, as I mentioned, the replace() method. Methods, just like functions, ARE procedural, so that line of code MUST exist within the procedural body, meaning it can exist inside main() or one of the functions that are called from main() or one of the functions called by those functions or one of the functions called by those functions... But, it can only exist inside a function that has scope of the object, so if myString is declared in setup(), replace() cannot be called from loop().

This is a trivial example of course, but there are some circumstances where you might need complex initialization of global variables (or const local variables). You can use an immediately invoked lambda expression:

String myString = []{
  String temporary = "Hello World!\n";
  temporary.replace("World", "Harry");
  return temporary;
}();

void setup() {
  Serial.begin(115200);
  Serial.print(myString);
}

void loop() {}

[]{ ... } defines an inline (lambda) function that takes no arguments, and by adding () you invoke/call that function.

The code above is equivalent to the following, but it's shorter, and it often doesn't make sense to add a named function that you're just going to use once, you want the logic of the initialization in the same place in your code as the variable you're initializing.

String getMyInitializedString() {
  String temporary = "Hello World!\n";
  temporary.replace("World", "Harry");
  return temporary;
}

String myString = getMyInitializedString();

Pieter

IILE are especially great for complex const initialization indeed. It helps enforce the const nature of it that you would have to loose otherwise.

pretty advanced for OP discovering C++ though :slight_smile:

J-M-L:
pretty advanced for OP discovering C++ though :slight_smile:

But neat to discover for others :wink:

Perehama:
But neat to discover for others :wink:

if you have time to kill, watch this (skip to 10:20 if you want to hear about IILE)

He is a newbie- don’t confuse him with Lambda functions- which I suspect the very few of us use them.

On the other hand, Henry- welcome to the forum.

Since you are just learning, do yourself a favor and do not use Strings. As you learn more and use Arduinos more, the evil String will bite you. Strings waste RAM and if used enough in a program, can use up memory and cause a crash that’s practically impossible to identify.

Read this.

Using char arrays is not as easy as using Strings, but it is the proper C++ method of handling strings.

SteveMann:
Using char arrays is not as easy as using Strings, but it is the proper C++ method of handling strings*.

*on a micro-controller with very limited memory and to be assessed elsewhere. (use of encoding and locale can be useful)