From Basic to Intermediate: Struct (VII)
Introduction
In the previous article, From Basic to Intermediate: Struct (VI), we examined how to begin creating a universal implementation of a simple data structure. Despite seeming unusual, this type of modeling is used much more often than most people think. This is because large databases use a very similar principle to organize and search data.
I understand that this topic, covered in our articles, may seem excessive to many. However, it is worth remembering that our goal is to explain things in such a way that in the future there will be no need to clarify certain details that, in my view, are trivial. But since most of you use these articles to learn from the experience and knowledge of other programmers, everything I can convey to you at the beginning will greatly assist you in the future, dear readers.
It is not enough to simply see working code; one must understand why it works and, if necessary, know how to adapt an implementation made by another programmer to suit our needs. To do this, it is necessary to know these concepts and understand how they can be applied.
As in the previous article, we began implementing something quite interesting to better understand how structures can be used within other structures, and perhaps you were intrigued by the outcome of the last code. This happened because we used a structure created for one purpose and ended up being able to apply it to another. In this case, the data originally had a double type, but in the end we were able to use data of any type.
However, what we showed is not what we wanted to achieve. For that, we need to advance a little further. But all this effort will pay off and be rewarded in the future. I promise. So, let us continue from where we left off in the previous article.
Structures of structures, part two: the return
In the previous article, we ended with the code shown below.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. template <typename T> 05. struct st_Data 06. { 07. //+----------------+ 08. private: 09. //+----------------+ 10. struct st_Reg 11. { 12. T h_value; 13. uint k_value; 14. }Values[]; 15. //+----------------+ 16. string ConvertToString(T arg) 17. { 18. if ((typename(T) == "double") || (typename(T) == "float")) return DoubleToString(arg, 2); 19. if (typename(T) == "string") return arg; 20. 21. return IntegerToString(arg); 22. } 23. //+----------------+ 24. public: 25. //+----------------+ 26. bool Set(const uint &arg1[], const T &arg2[]) 27. { 28. if (arg1.Size() != arg2.Size()) 29. return false; 30. 31. ArrayResize(Values, arg1.Size()); 32. for (uint c = 0; c < arg1.Size(); c++) 33. { 34. Values[c].k_value = arg1[c]; 35. Values[c].h_value = arg2[c]; 36. } 37. 38. return true; 39. } 40. //+----------------+ 41. string Get(const uint index) 42. { 43. for (uint c = 0; c < Values.Size(); c++) 44. if (Values[c].k_value == index) 45. return ConvertToString(Values[c].h_value); 46. 47. return "-nan"; 48. } 49. //+----------------+ 50. }; 51. //+------------------------------------------------------------------+ 52. #define PrintX(X) Print(#X, " => ", X) 53. //+------------------------------------------------------------------+ 54. void OnStart(void) 55. { 56. const string T = "possible loss of data due to type conversion"; 57. const uint K[] = {2, 1, 4, 0, 7, 5, 3, 6}; 58. 59. st_Data <string> info; 60. string H[]; 61. 62. StringSplit(T, ' ', H); 63. info.Set(K, H); 64. PrintX(info.Get(3)); 65. } 66. //+------------------------------------------------------------------+
Code 01
Although Code 01 works, it is somewhat annoying. This is because when we compile it, we get a response similar to the one shown below.

Figure 01
Things like this (as shown in Figure 01) cause some inconvenience. This happens because, depending on the type of implementation, compiler messages can lead to errors in the code in the future. This is not because the code is incorrect, but because the compiler may be warning us about a potential critical error. By ignoring error messages, we may end up overlooking a truly important message.
In any case, when executing Code 01, we will get the following response.

Figure 02
Interesting, isn't it? But before we continue, let's solve the problem shown in Figure 01. There are several ways to do this. However, they all ultimately lead to the same result: explicit conversion. Therefore, the way in which we achieve explicit conversion does not matter. What matters is that it takes place. To do this, simply change Code 01 to something like this:
. . . 15. //+----------------+ 16. string ConvertToString(T arg) 17. { 18. if (typename(T) == "double") return DoubleToString((double)arg, 2); 19. if (typename(T) == "float") return DoubleToString((float)arg, 2); 20. if (typename(T) == "string") return (string)arg; 21. return IntegerToString((long)arg); 22. } 23. //+----------------+ 24. public: 25. //+----------------+ . . .
Code 02
Upon seeing that the solution to the problem in Figure 01 is the code snippet in Code 02, you are probably somewhat disappointed. Many likely expected that a full set of instructions and functions would be created, and in the end, we only need to do what is shown in this Code 02. That is part of the process. How disappointed we feel usually depends on how much we expected in the first place. Jokes aside, let us return to the code and understand how to make it more extensible so that it can handle different types of data without significant changes.
You might think this will be complicated. However, before explaining how to do this, I need you to truly understand how and why to link one element of an array to another element of another array.
The concept itself is very simple. It is merely about creating a translation. In other words, if we know the array element that will serve as the key, then the response will essentially be an element of another array. That is exactly what we will do with Code 01. And why not use a multidimensional array for this? The reason is that, although a multidimensional array would be the best option in this case, it is not suitable because we are using it as a proof of concept. In other words, this is about demonstrating the use of a specific type of language resource.
Alright, I assume that what we are doing has been explained clearly enough, and I want you to look again at Code 01 and tell me what prevents its use not only for translating values but also in other similar contexts.
Do not rush to conclusions; think about it first. Now we will look at one of the many ways to free up the code so that we can place anything into it. However, if we try to expand the code, we will notice that the problem lies in the structure declared in line 10. That is the issue, but not in the sense you might think.
The problem with the structure in line 10 is that it prevents the main structure from being used more universally. Since I understand that this is complex and takes time, we will continue with the article. But I ask you to read and reread this article and the previous ones in order to understand one thing.
Structures, like other types of constructs, are forms of representing more or less complex data. The way to solve a problem depends on its real complexity. Some tasks can be solved using discrete and simple types of data, such as floating-point representations or integer values.
When the task becomes more complex, discrete types may not be sufficient. In that case, we will need more complex types of data, such as arrays and unions. If the problem remains complex, we need an equally complex type: structures.
Thus, the structure we declared in line 10 of Code 01 is nothing more than a complex type. This must be understood in order to grasp what we are going to do.
First, we must take this structure from line 10 of the structure defined in line 04, while preserving Code 01. However, by doing so, we will create confusion in the information that will confuse you even more if you did not understand or could not follow the previous articles. This is because there is no way to implement the changes gradually, and this needs to be done in a very small number of steps. The first step is shown just below:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. struct st_Reg 05. { 06. string h_value; 07. uint k_value; 08. }; 09. //+----------------+ 10. struct st_Data 11. { 12. //+----------------+ 13. private: 14. //+----------------+ 15. st_Reg Values[]; 16. //+----------------+ 17. public: 18. //+----------------+ 19. bool Set(const uint &arg1[], const string &arg2[]) 20. { 21. if (arg1.Size() != arg2.Size()) 22. return false; 23. 24. ArrayResize(Values, arg1.Size()); 25. for (uint c = 0; c < arg1.Size(); c++) 26. { 27. Values[c].k_value = arg1[c]; 28. Values[c].h_value = arg2[c]; 29. } 30. 31. return true; 32. } 33. //+----------------+ 34. string Get(const uint index) 35. { 36. for (uint c = 0; c < Values.Size(); c++) 37. if (Values[c].k_value == index) 38. return Values[c].h_value; 39. 40. return NULL; 41. } 42. //+----------------+ 43. }; 44. //+------------------------------------------------------------------+ 45. #define PrintX(X) Print(#X, " => ", X) 46. //+------------------------------------------------------------------+ 47. void OnStart(void) 48. { 49. const string T = "possible loss of data due to type conversion"; 50. const uint K[] = {2, 1, 4, 0, 7, 5, 3, 6}; 51. 52. st_Data info; 53. string H[]; 54. 55. StringSplit(T, ' ', H); 56. info.Set(K, H); 57. PrintX(info.Get(3)); 58. } 59. //+------------------------------------------------------------------+
Code 03
Warning: to make the code (and what we are going to do) as simple and clear as possible, we will take a step back and use the string type. Please note that the generalized version of the structure we were building no longer exists, and the execution result still corresponds to Image 02.
Perhaps if you look at Code 03, you might think: «Okay, you said this was complicated, but so far it's still simple. What's the complexity?» Well, then let us proceed. The second point that needs to be changed is that the Set and Get functions (which you see in lines 19 and 34, respectively) ARE NOT functions of st_Data; they are functions of st_Reg.
Now I ask: what are they doing in st_Data? The answer: They make it difficult for the structure to function in a more universal mode, which prevents it from handling data of any type. Therefore, we need to remove these functions from the st_Data structure as it appears in Code 03. For greater simplicity, let us look at what the corrected snippet will look like. It is shown below.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. struct st_Reg 05. { 06. //+----------------+ 07. private: 08. //+----------------+ 09. string h_value; 10. uint k_value; 11. //+----------------+ 12. public: 13. //+----------------+ 14. void Set(const uint arg1, const string arg2) 15. { 16. k_value = arg1; 17. h_value = arg2; 18. } 19. //+----------------+ 20. uint Get_K(void) { return k_value; } 21. //+----------------+ 22. string Get_H(void) { return h_value; } 23. //+----------------+ 24. }; 25. //+----------------+ 26. struct st_Data 27. { 28. //+----------------+ 29. private: 30. //+----------------+ 31. st_Reg Values[]; 32. //+----------------+ 33. public: 34. //+----------------+ 35. bool Set(const st_Reg &arg) 36. { 37. if (ArrayResize(Values, Values.Size() + (Values.Size() == 0 ? 2 : 1)) == INVALID_HANDLE) 38. return false; 39. 40. Values[Values.Size() - 1] = arg; 41. 42. return true; 43. } 44. //+----------------+ 45. st_Reg Get(const uint index) 46. { 47. for (uint c = 0; c < Values.Size(); c++) 48. if (Values[c].Get_K() == index) 49. return Values[c]; 50. 51. return Values[0]; 52. } 53. //+----------------+ 54. }; 55. //+------------------------------------------------------------------+ . . .
Code 04
«What madness is this?» Calm down, this is only the beginning. Now we have not one but two structures for combining data into the new st_Data structure. But before moving on to the main code (which will be in OnStart), we need to understand what is happening here.
In fact, although this code snippet works the same way as Code 03, there are several aspects here that are completely different from what we are used to. Nevertheless, in my view, this is still beginner-level code, since we are dealing with very simple things.
To begin with, it is important to remember that st_Reg is a structure designed to work with structural code. In other words, we will not directly interact with variables, but we will create a context in which we can manage them.
Essentially, st_Reg works the same way as it did before we started the topic of nested structures. Now begins the part that complicates things for many beginners, especially if they are unclear on the basic concepts of what a variable is and how to work with data types. Let us understand what is happening in the second structure, called st_Data. Since st_Reg is a complex data type, in line 31 we can declare a variable, which in this case is an array, to store data of that type—that is, st_Reg. So far, you probably do not see any problems, do you?
However, if we look at line 35, we see that things start to lose meaning, especially if we pay attention to line 37. My goodness, what is happening there?! In this line, we are simply trying to allocate memory space, dear readers. However, there is a small detail that complicates things a bit. The fact is that in MQL5, WE CANNOT RETURN POINTERS. Therefore, in the function shown in line 45, there is a small drawback that we are trying to fix in line 37.
So, pay attention. If we try to find a value inserted into the st_Data structure and DO NOT FIND IT, we have to return invalid data. In languages like C and C++, we do this by typically returning a null value. However, here in MQL5, WE CANNOT DO THAT. We need a little trick. Therefore, when in line 37 we attempt to allocate the first block to add data of type st_Reg, we allocate two memory cells. The first will be empty. However, the second will be assigned the value corresponding to line 40.
Since this is the first element, two positions will be allocated to it. Starting from the next call, line 37 will determine that at least two elements have already been allocated, and will allocate only one more. Thus, this will happen with each new call to the Set function of the st_Data structure. Please note that this has nothing to do with the Set procedure of the st_Reg structure, and there is a reason for this, which will be discussed later.
So, since the Get function of the st_Data structure is directly related to the explanation of the Set structure, we only need to understand that the value received as an argument by the Get function does not indicate which index in the Values array is being searched for, but rather which value is physically stored in that specific element. Therefore, we need a loop to search for a specific value in the st_Reg structure. We will discuss this issue later. In general, that's it.
Now we can review the main code. If you recall, the code we saw in the snippet from Code 04 could very well be placed in a header file, and it would work without issues. But before showing how to do this in order to generalize the code, we need to look at the rest of it. It is shown below. It is shown below.
. . . 55. //+------------------------------------------------------------------+ 56. #define PrintX(X) Print(#X, " => [", X, "]") 57. //+------------------------------------------------------------------+ 58. void OnStart(void) 59. { 60. const string T = "possible loss of data due to type conversion"; 61. const uint K[] = {2, 1, 4, 0, 7, 5, 3, 6}; 62. 63. st_Data info; 64. string H[]; 65. 66. StringSplit(T, ' ', H); 67. for (uint c = 0; c < H.Size(); c++) 68. { 69. st_Reg reg; 70. 71. reg.Set(K[c], H[c]); 72. info.Set(reg); 73. } 74. 75. PrintX(info.Get(3).Get_H()); 76. PrintX(info.Get(13).Get_H()); 77. } 78. //+------------------------------------------------------------------+
Code 05
And so begins the most fun and exciting part. Since you have probably already understood most of this code, as it was shown earlier, let's move on to the new part. This specifically concerns the loop in line 67, as well as lines 75 and 76.
Let's start with the loop. Since each element to be placed into the st_Data structure is of type st_Reg, we need line 71 to create an st_Reg structure, so that we can then store an element of type st_Reg in the st_Data structure using line 72. Now the question: why do we not do this directly in the st_Data structure? The answer is that if the recording of elements of type st_Reg were done directly in the st_Data structure, we would not be able to extend this structure later. But do not worry, you will soon understand it.
After all the elements have been written into the st_Data structure, we can use lines 75 and 76 to test this structure. To do this, in line 75 we search for a string whose index is three. And, looking at lines 60 and 61, you can see what value this index holds. In line 76, in turn, a search will be performed for an element whose index is 13. Since this index is not defined in line 61, the returned value will be the one defined in line 51 of Code 04.
With this preliminary knowledge, we can run the code. Thus, we will see the following result:

Figure 03
In other words, it works perfectly. Now we can generalize a significant part of the code, but to do so we will move on to a new topic. This way, we can calmly study what we have already done, and then try to understand what still needs to be done to make the generalizations.
Structures of structures, part three, revenge
If you found the information in the previous topic confusing, get ready, because things are about to get even more interesting. Here, things truly become more complex. So pay attention to the following fact. In Code 04 from the previous topic, the st_Data structure can only accept one data type, namely the st_Reg type, but this does not make it universal. This restricts the st_Data structure to only what is defined in the st_Reg structure, even if they are not related to each other.
However, if we slightly modify the code of the st_Data structure, we can free up its resources so that it can work with different data types. Note what I just said. When the st_Data structure becomes a template, it will not be completely free from the st_Reg structure, which is related to the Get function that will remain tied to the st_Reg type. Nevertheless, it is worth the effort.
As indicated above, all we need to do is transform the st_Data structure into a template and simultaneously adjust the main code to match this template, which the compiler will have to generate. This is done with the following code.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. struct st_Reg 05. { 06. //+----------------+ 07. private: 08. //+----------------+ 09. string h_value; 10. uint k_value; 11. //+----------------+ 12. public: 13. //+----------------+ 14. void Set(const uint arg1, const string arg2) 15. { 16. k_value = arg1; 17. h_value = arg2; 18. } 19. //+----------------+ 20. uint Get_K(void) { return k_value; } 21. //+----------------+ 22. string Get_H(void) { return h_value; } 23. //+----------------+ 24. }; 25. //+----------------+ 26. template <typename T> 27. struct st_Data 28. { 29. //+----------------+ 30. private: 31. //+----------------+ 32. T Values[]; 33. //+----------------+ 34. public: 35. //+----------------+ 36. bool Set(const T &arg) 37. { 38. if (ArrayResize(Values, Values.Size() + (Values.Size() == 0 ? 2 : 1)) == INVALID_HANDLE) 39. return false; 40. 41. Values[Values.Size() - 1] = arg; 42. 43. return true; 44. } 45. //+----------------+ 46. T Get(const uint index) 47. { 48. for (uint c = 0; c < Values.Size(); c++) 49. if (Values[c].Get_K() == index) 50. return Values[c]; 51. 52. return Values[0]; 53. } 54. //+----------------+ 55. }; 56. //+------------------------------------------------------------------+ 57. #define PrintX(X) Print(#X, " => [", X, "]") 58. //+------------------------------------------------------------------+ 59. void OnStart(void) 60. { 61. const string T = "possible loss of data due to type conversion"; 62. const uint K[] = {2, 1, 4, 0, 7, 5, 3, 6}; 63. 64. st_Data <st_Reg> Info_1; 65. string H[]; 66. 67. StringSplit(T, ' ', H); 68. for (uint c = 0; c < H.Size(); c++) 69. { 70. st_Reg reg; 71. 72. reg.Set(K[c], H[c]); 73. Info_1.Set(reg); 74. } 75. 76. PrintX(Info_1.Get(3).Get_H()); 77. PrintX(Info_1.Get(13).Get_H()); 78. } 79. //+------------------------------------------------------------------+
Code 06
Theoretically, Code 06 can contain any type of data structure or any data type inside the st_Data structure. In theory this is true. The reason lies precisely in the Get function, located in line 46 of Code 06. To make the code more universal, we only needed to add line 26 and replace the references to st_Reg in lines 32, 36, and 46 with the type T. After that, we needed to modify the declaration in line 64 so that the compiler could generate the corresponding structure.
The result of executing Code 06 will be the same as when executing Code 05, that is, figure 03. However, we are still, in a sense, tied to the st_Reg structure, although this binding (which is also a problem) can also bring some benefits. It all depends on the needs, level of creativity, and level of knowledge of each reader on certain topics. Note the following. The only remaining connection between the st_Data and st_Reg structures is the so-called Get_K function, located in line 49. This is the only link that still remains. Since the st_Reg structure can also be overloaded, in this case we can use different types.
But since such things can give rise to complex details that are difficult to understand in the final part of the article, we will not discuss them now.
However, even so, we can do something that I find interesting, and it can also be explained in the remaining part of the article. It concerns exactly line 49 of Code 06. Now pay attention, dear readers: in the article From Beginner to Intermediate Level: Overloading, we talked about a very simple and interesting way to use function and procedure overloading. In other articles of this series, we also showed that this can be done using names identical to those contained in the standard library.
Now here is the interesting part: what if in Code 06 we create a way to overload the Get_K function shown in line 49? What possibilities would this open up? As we have already said, this is where creativity and the application of concepts make things very interesting. This is because, if you look closely, you will notice that the st_Reg structure (shown in Code 06) contains only two variables. But we can overload the st_Reg structure to obtain another structure with more variables or even with completely different data types inside the structure.
However, by doing this, we would not necessarily have to delete the original st_Reg structure or modify the st_Data structure already created in Code 06. Since I am not sure that you understand what I mean, let us look at a code snippet where we can see what I am trying to show. This code is below.
001. //+------------------------------------------------------------------+ 002. #property copyright "Daniel Jose" 003. //+------------------------------------------------------------------+ 004. struct st_Reg 005. { 006. //+----------------+ 007. private: 008. //+----------------+ 009. string h_value; 010. uint k_value; 011. //+----------------+ 012. public: 013. //+----------------+ 014. void Set(const uint arg1, const string arg2) 015. { 016. k_value = arg1; 017. h_value = arg2; 018. } 019. //+----------------+ 020. uint Get_K(void) { return k_value; } 021. //+----------------+ 022. string Get_H(void) { return h_value; } 023. //+----------------+ 024. }; 025. //+------------------------------------------------------------------+ 026. struct st_Bio 027. { 028. //+----------------+ 029. private: 030. //+----------------+ 031. string h_value; 032. string b_value; 033. uint k_value; 034. //+----------------+ 035. public: 036. //+----------------+ 037. void Set(const uint arg1, const string arg2, const string arg3) 038. { 039. k_value = arg1; 040. h_value = arg2; 041. b_value = arg3; 042. } 043. //+----------------+ 044. uint Get_K(void) { return k_value; } 045. //+----------------+ 046. bool Get_Bio(string &arg1, string &arg2) 047. { 048. arg1 = h_value; 049. arg2 = b_value; 050. 051. return true; 052. } 053. //+----------------+ 054. }; 055. //+------------------------------------------------------------------+ 056. template <typename T> 057. struct st_Data 058. { 059. //+----------------+ 060. private: 061. //+----------------+ 062. T Values[]; 063. //+----------------+ 064. public: 065. //+----------------+ 066. bool Set(const T &arg) 067. { 068. if (ArrayResize(Values, Values.Size() + (Values.Size() == 0 ? 2 : 1)) == INVALID_HANDLE) 069. return false; 070. 071. Values[Values.Size() - 1] = arg; 072. 073. return true; 074. } 075. //+----------------+ 076. T Get(const uint index) 077. { 078. for (uint c = 0; c < Values.Size(); c++) 079. if (Values[c].Get_K() == index) 080. return Values[c]; 081. 082. return Values[0]; 083. } 084. //+----------------+ 085. }; 086. //+------------------------------------------------------------------+ 087. #define PrintX(X) Print(#X, " => [", X, "]") 088. //+------------------------------------------------------------------+ 089. void CheckBio(st_Data <st_Bio> &arg) 090. { 091. string sz[2]; 092. 093. Print("Checking data in the structure..."); 094. for (uint i = 7; i < 11; i += 3) 095. { 096. Print("Index: ", i, " Result: "); 097. if (arg.Get(i).Get_Bio(sz[0], sz[1])) 098. ArrayPrint(sz); 099. else 100. Print("Failed."); 101. } 102. } 103. //+------------------------------------------------------------------+ 104. void OnStart(void) 105. { 106. const string T = "possible loss of data due to type conversion"; 107. const string M[] = {"2", "cool", "4", "zero", "mad", "five", "what", "xoxo"}; 108. const uint K[] = {2, 1, 4, 0, 7, 5, 3, 6}; 109. 110. st_Data <st_Reg> Info_1; 111. st_Data <st_Bio> Info_2; 112. 113. string H[]; 114. 115. StringSplit(T, ' ', H); 116. for (uint c = 0; c < H.Size(); c++) 117. { 118. st_Reg reg; 119. st_Bio bio; 120. 121. reg.Set(K[c], H[c]); 122. bio.Set(K[c], M[c], H[c]); 123. 124. Info_1.Set(reg); 125. Info_2.Set(bio); 126. } 127. 128. PrintX(Info_1.Get(3).Get_H()); 129. PrintX(Info_1.Get(13).Get_H()); 130. CheckBio(Info_2); 131. } 132. //+------------------------------------------------------------------+
Code 07
When executing Code 07, an image very similar to this will appear in the terminal.

Figure 05
Oh my God! What a wild and crazy creation we have made! Calm down, my dear readers, what interests us here is precisely the information highlighted in Image 05, which was created by the procedure in line 89, on which we will focus our explanation, since most of the code is easy to understand. Understanding this procedure in line 89 is crucial to grasping what will be covered in the next article.
But before explaining what is happening in the procedure in line 89, we need to understand a few additional points. Let us start with line 26, where a new structure is created. It should be noted that it has a similar foundation to the st_Reg structure, but the similarity ends there, as the st_Bio structure contains more variables and a different set of operations within its context. What matters to us is the function in line 44. This is because it performs the same function as line 20, since it has the same goals and objectives. And this is important for what we will do next.
Please also note that the st_Data structure (from Code 07) is exactly the same as the st_Reg structure in Code 06. The only real change is the presence of the st_Bio structure. After this, we can move on to the main OnStart procedure, which is the entry point of our code. Notice that we have added some additional elements here that were not present in Code 06. These examples are precisely intended to show how flexible the st_Data structure can become if the implementation phase of the code is carefully thought out.
Essentially, we added lines 107 and 111. Now, please concentrate. Notice that the difference between lines 110 and 111 is precisely the type of data that will be placed into the st_Data structure. Therefore, inside the loop in line 116, we add a new variable in line 119, which will receive values in line 122, and in line 125 we assign or add a new piece of data to the structure. In this case, the data type will differ from the data type in line 124. So far, everything has happened as predicted in Code 06.
However, this is where the complexities begin, and at the same time, the more interesting parts: we have line 130, which will lead to the execution of the procedure in line 89. Now let us move on to the most interesting part. Please note that we are inside the loop in line 94, and what interests us most is line 97, which we should compare with line 128. What is the difference between them? Practically none, except that, since line 76 returns a structural type referring to the data type of the variable declared in line 62, there are no differences between the two lines.
In the article «From Basic to Intermediate: Variables (III)», we explained that a function is a special type of variable. Here, this concept is applied in a very interesting way, because based on the response we receive from the function in line 76, we can point to one or another data type, in this case, to a structure. Without the use of structural programming, it would be practically impossible (or extremely difficult) to create what is being done here. The point is that in line 97, a reference to the st_Bio structure is used. In line 128, we point to the st_Reg structure, and since both structures are inside the st_Data structure, we can process different types of information or datasets in the same way.
To understand what is really happening here, you need to practice and experiment. You will not be able to understand by simply looking at the code with little programming experience. And remember: we are still working with material that, in my view, is at a beginner level.
Final thoughts
In today's article, we showed how to approach solving problems by structuring them and creating a simpler and more appealing solution. Although the material presented here is educational and, therefore, not production code, it is essential to thoroughly grasp the concepts and knowledge presented here. Thus, in the future, you will be able to follow the code we will show, because as we progress, we will be able to reveal deeper and more interesting details of programming, which would be impossible if we had to explain every line of code.
Therefore, take this opportunity to carefully study the material from the index, without rushing. Study and apply this knowledge in practice, because in the next article we will continue from where we left off today. We have not yet finished discussing structural programming and how we can take advantage of it before moving on to object-oriented programming.
Translated from Portuguese by MetaQuotes Ltd.
Original article: https://www.mql5.com/pt/articles/15912
Warning: All rights to these materials are reserved by MetaQuotes Ltd. Copying or reprinting of these materials in whole or in part is prohibited.
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.
Trend Criteria. Conclusion
Market Simulation (Part 17): Sockets (XI)
Neuro-Structural Trading Engine — NSTE (Part II): Jardine's Gate Six-Gate Quantum Filter
From Novice to Expert: Adaptive Risk Management for Liquidity Strategies
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use