OOP, templates and macros in mql5, subtleties and uses - page 2

 
Ilya Malev:

I've had many situations of declaring static fields in classes which are initialized globally (before OnInit), as long as you re-declare static field right after class description, and before declaring global variable of its instance, there was never any problem with static field initialization (because in this case it is considered global and initialized before the class instance as I understand). That is, you just need to refuse declaring static variables inside methods and functions and there's no problem.

Yes, that's right, it's initialized right away in regular classes. But it's not initialized in template ones:

template<typename T>
class A
{
 public: 
  static int a;
};

template<typename T>
int A::a=10;

int f() { return A<int>::a; }

int a= f();

void OnStart()
{
  Print(a); // Результат: 0
};
 
Alexey Viktorov:

You can not completely refuse to declare static variables inside methods and functions, but at least do not initialize other static variables with those methods or functions which contain static variables.

In this example, at first static int b variable will be initialized but static int f variable inside int a(int n) function will not be initialized yet and as the result we will get gibberish.

By the way, yes, it is one more bug. I.e. besides separate initialization of static/global variables, the code initializes static variables themselves in a wrong order. So you say "do not initialize other static variables with those methods or functions which contain static variables" - how do you actually suggest observing this? Each function is independent and exists by itself. It has its own implementation, which is subject to change. Suppose it didn't have a static variable before, and then you decided to add it, which means that something might go wrong somewhere, because it was designed not to have a static variable in the function. And how are you going to control all this?

 
I don't understand this kind of decision to give up this or that. Why give up? What for? When you can solve the problem and not deny yourself anything. Well, everyone has his own choice...
 
Alexey Navoykov:

By the way, yes, this is another bug, i.e. besides separate initialization of static/global remeasured, it initializes static variables themselves in the wrong order. So you say "do not initialize other static variables with those methods or functions which contain static variables" - how do you actually suggest observing this? Each function is independent and exists by itself. It has its own implementation, which is subject to change. Suppose it didn't have a static variable before, and then you decided to add it, which means that something might go wrong somewhere, because it was designed not to have a static variable in the function. And how are you going to control all this?

It's not a problem at all. It is enough to refuse initialization of variables by functions and everything will fall into place.

int a(int n)
{
 static int f=7;
 return(f+=n);
}

void OnTick()
{
 static int b;
 b=a(9);
}
It will work fine. What's the problem? One line?
 
Alexey Viktorov:

It'll work for a hoot and a holler. What's the problem? One line?

So do you understand that the logic is different here? Why declare b as static if you assign a value to it on every call?
 
Alexey Navoykov:
So, do you understand that the logic is different here? Why declare b static at all if you assign a value to it on each call?

I agree. I messed up a bit in a hurry. But the 'b' variable can be assigned a value under some condition and instead of 9 values can be passed into the function depending on the condition.


But in your example, does the 'a' variable must be initialized globally?

template<typename T>
class A
{
 public: 
  static int a;
};

template<typename T>
int A::a=10;

int f() { return A<int>::a; }

int a= f();

void OnStart()
{
  Print(a); // Результат: 0
};

There is no other option in the script, and in the Expert Advisor you can declare the variable on the global level and initialize it in OnInit()

It is enough to understand and observe the initialization sequence. Global variables first, then static variables and then local variables as they appear in the code.

This very example violates the documentation's recommendation not to initialize variables with functions. It was easier for the developers to write such a warning than explain where they can and cannot do that.

Remove static from your example and get your desired result.

 
Alexey Viktorov:

But must the 'a' variable in your sample be initialized globally?

Not necessarily, but it's more convenient for me. If it is a constant (and globally visible constants are declared mostly, if the code is smart), then there is no other choice.

There is no other option in the script, and in the EA you can declare a variable globally and initialise it in OnInit()

It is enough to understand and observe the initialization sequence. Global variables first, then static variables and then local variables as they appear in the code.

This very example violates the documentation's recommendation not to initialize variables with functions. It was easier for the developers to write such a warning than explain where they can and cannot.

Remove static from your example and get the desired result.

Concerning everything in yellow, I have one question: WHY? I've already found how to solve the problem.
 
Updated the file on the previous page. Corrected a minor flaw.
 
Alexey Navoykov:

Not necessarily, but it's more convenient for me. If it's a constant (and global visibility mostly declares constants, if the code is competent), there's no other choice here.

Concerning everything in yellow, I have one question: WHY? I've already found how to solve the problem.

You have found a way to create it.

 
Alexey Navoykov:

Yes, that's right, in regular classes it is initialised immediately. But in template classes it is not:

You are trying to use a static fieldof a class at the initialization stage before at least 1 instance of that class was created. In my opinion, this is a perversion... This is how it works normally:

template<typename T>
class A
{
 public: 
  A(){}
  static int a;
  int f(){return a;}
};

template<typename T>
int A::a=10;

A<int> _a;


int a= _a.f();

void OnStart()
{
  Print(a);
};
The principle of encapsulation in general suggests that such fields should be hidden rather than public.
Reason: