Русский 中文 Español Deutsch 日本語 Português
preview
From Basic to Intermediate: Variables (I)

From Basic to Intermediate: Variables (I)

MetaTrader 5Examples | 24 January 2025, 09:44
2 220 0
CODE X
CODE X

Introduction

The materials presented here are for didactic purposes only. The application should not be viewed for any purpose other than to learn and master the concepts presented.

The purpose of this article is to help and explain some concepts and usage of MQL5 for various activities. It is not only focused on creating indicators, scripts or Expert Advisors. The main goal here is the transfer of knowledge.

Many of you already know me from other articles. However, since those articles are aimed at programmers with some experience, and many have expressed interest in learning more about the subject, I thought it would be interesting to create another series to provide some basic explanations. This does not mean that we will discuss the topics that everyone already knows, making the articles boring and meaningless. On the contrary, I will try to provide materials that are truly interesting and exciting. But since there are already many articles in the other direction waiting to be published, now I have the opportunity to share my knowledge in this new series. We will cover questions related to progression from the basic to what I consider the intermediate level. Nevertheless, we will learn concepts within MQL5, and some of them will be useful for those who are going to learn other programming languages.

We will start this article with the most basic and fundamental part of programming in general. Today we will talk about variables. Since I like to keep things clearly separated, we'll start the article with a new topic.


Variables. Fundamentals of programming

Many people mistakenly believe that computer programs are built on functions and methods. But this assumption is wrong. Computer programs are mostly built on variables. No program is created or provided for any other purpose. The purpose is always to make the variable known and usable.

Of course, this idea may seem strange to readers, especially when all the courses and books tend to focus on functions and methods, implying that these are the basic principles of programming. However, I am not here to cause controversy or disagreement. I am here to make my contribution. While the terms known as functions and methods are very important, they are nothing more than some kind of computed variable. This will become more clear in the next articles.

In this first article, I want to present the concept of a variable to you. And yes, there are differences between variables. Knowing what each type is and how to best use each one is the difference between a well-written program and a simple program that does a specific task.

Let's start with the fact that there are two different kinds of variables: those that can change value and those that cannot change value. In the second case, such variables are referred to as constants. However, since computer programs running in user mode will always always be present in RAM, the word constant is not so appropriate. The reason is that since the value is in RAM, it can be modified in some way. Who hasn't tried CRACK to circumvent any limitations? In many cases, CRACK acts directly in some part of the executable file, either in RAM or on disk.

When intervention occurs on disk, CRACK acts directly on top of constants. This is because the values presented on the disk do not change over time. They tend to remain unchanged. Thus, CRACK actually acts on a value that only appears to be constant. But it is variable precisely because CRACK is able to modify it. However, when it comes to RAM, some parts may be considered constants, and attempting to change such values will be considered an error. The processor must notify the operating system so that it takes the necessary measures. So the first thing to note is that variables can be constant or not. If the values are in RAM, our application can determine what will be constant and what will be variable. In any other scenario, variables should never be treated as constants.

Having made this small clarification, we can move on to the next step, where the same concept will be implemented in practice. Let's start little by little. Some concepts are quite difficult to separate, so at first it all may seem quite complicated. Be patient, my dear reader. Soon you will feel more confident and find it easier to do various things. Let's study it all piece by piece, starting with what is shown below.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     int     value1;
07.     char    value2;
08.     long    value3;
09. 
10.     value1 = 10;
11.     value2 = 5;
12.     Print("Result: ", value1 + value2 + value3);
13. }
14. //+------------------------------------------------------------------+

Code 01

This code is very simple and basic. Here we have three variable declarations located in lines 06, 07 and 08. There's no need to worry about types yet. We'll talk about this in more detail in another article. For now, just pay attention to what is being explained. Although we have three variables declared here, two of them are actually temporary constants, and the other one is not being referenced or, if we use the correct term, initialized. Often you may think that this code will produce a certain result. But not understanding how different thinks work or ignoring them can put your whole work at risk.

To understand this, let's look at the compiler outputs. If you use MetaEditor, the result will look like in figure 01.


Figure 01:

In my caseб I use another tool to edit codes, but it also uses the MetaTrader 5 compiler to create applications. The output is as follows:


Figure 02

Note that in both cases the compiler returns a warning, and we should be careful when any warning appears. Because often a warning indicates that our application may behave in an unexpected way. If we need to display some point related to the compiler output, we will do it according to the model shown in Figure 02. However, the result will be very similar to the messages we would see when using MetaEditor. So please read carefully, so you can follow all the next articles.

Now suppose we ignored this compiler warning. Some of them can be ignored, while others cannot. And we decided to launch this application, already compiled in MetaTrader 5. What kind of results do you expect to get? You probably expect to get the value 15, because in line 10 we say that the variable value1 is equal to 10, and in line 11 we say that the variable value2 is equal to 5. So when line 12 is executed, the expected result will be the sum of these two values, right? Let us have a look. The result is shown below.


Figure 03

So what happened here? Is this really possible?! Yes, dear reader, this is possible. You can see this for yourself. But your wondering is quite justified, because you clearly expected the printed value to be 15. Why is this zero value generated? The reason lies precisely in the value3 variable. Since it participates in the computation and HAS NOT been properly initialized, it can contain any value. Depending on this value, which in programming we call "junk", it will make the final result incorrect.

In this case we have two alternatives. The first is to initialize value3 correctly. The second is to remove value3 from the calculation performed in line 12. Since our goal at this stage is to get a result equal to 15, we will choose the second option. So in the same code 01 we will change line 12 as shown below.

Print("Result: ", value1 + value2);

In this case, when you try to compile the code, the compiler will generate the following warning.


Figure 04

Note that the warning is different from the one we saw earlier. We analyze it and decide that in this particular case it can be ignored. We launch the application in MetaTrader 5 and get the result shown below.


Figure 05

It worked! We achieved exactly what we expected. Now let's go back to the source code 01 to understand some basic concepts. As mentioned above, the variables value1 and value2 can and should be considered as temporary constants. Why? The reason for this is precisely because they DO NOT change their value throughout the code, they always have the same value. There is one problem here, however, and this is where things get a little interesting.

Although value1 and value2, as well as value3 are variables, we as programmers can change this. This way we are guaranteed that the value assigned to this variable WILL NOT CHANGE, regardless of any mistakes we may make while writing the code. Many experienced programmers who work with more complex and intricate code prefer to use languages that allow this kind of control. In such cases, you as programmers can say: "Listen, compiler, this variable should not be treated as a variable, I want it to be a constant." And the compiler will help you ensure that this variable is stored as a constant. To achieve this control in MQL5, we use a reserved word. Thus, code that produces the same result as the previous one can be written in a different way. But before we get into this in practice, let's look at something else. As a result, we create the following code.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     const int   value1;
07.     char        value2;
08. 
09.     value1 = 10;
10.     value2 = 5;
11.     Print("Result: ", value1 + value2);
12. }
13. //+------------------------------------------------------------------+

Code 02

If you try to compile code 02, the compiler will not let you do so due to the errors shown below.


Figure 06

In this case, we encountered two errors: one generated in the sixth line, and the other in the ninth. Now let's deal with the errors, because the most important thing is not just to correct them, but to understand what they tell us. This is because an error is not always an error in itself. Often this can be a simple compiler warning that you are trying to do something you shouldn't be doing. This is exactly the case with the error in the ninth line.

Please be careful here note as this can greatly help you in MQL5 programming. When we define a variable as a constant, any attempt to change its value while the code is running will be considered a SERIOUS error. We haven't launched our app yet. Despite this, the MQL5 compiler already warns us about the possibility of a serious error during execution. For this reason, it does not allow the 02 code to be compiled. This happens because we told the compiler that the variable value1 is NOT a variable but a CONSTANT. To do this, the word 'const' is used before the operator, as shown in the sixth line of code 02. Many less experienced programmers would prefer to remove the word 'const' from the declaration in line 6. This is not an error, but it does remove the compiler's help in preventing the value1 variable from being treated as a constant. This, in turn, can lead to other problems in the application, such as generating incorrect values at certain times, without understanding why the code does not behave as expected.

But there is another problem, and it is this one that causes the error in the sixth line, as seen in image 06. This problem caused code 01 to generate an incorrect value at runtime when the value3 variable was used in the calculation of line 12, which referenced code 01.

The problem lies precisely in the initialization of values. Some languages initialize the values of variables, usually to zero by default. However, in this case, compiler developers must be careful to ensure that variables treated as constants do not have an explicitly defined value. Arbitrary and implicit assignment of zero to any uninitialized variable may adversely affect the final application. This is precisely because of the detail shown in code 02: if the compiler automatically assigned a value of zero to every uninitialized variable, the result of the operation in line 11 would be completely wrong. And you, as programmers, would spend a lot of time trying to figure out why. So an error is not always an error. Likewise, compiler warnings do not always need to be fixed. In some cases, we may ignore some information that they indicate.

Okay, now that we've cleared that up, how should we write code 02 so that it can be compiled? Considering that we really want things to be this way, the code should be changed as shown below.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     const int   value1 = 10;
07.     char        value2;
08. 
09.     value2 = 5;
10.     Print("Result: ", value1 + value2);
11. }
12. //+------------------------------------------------------------------+

Code 03

Now everything is correct. This code 03 will be compiled. The result can be seen in image 05. However, you may have a doubt: why program this exactly as the author shows? Wouldn't it be easier to use something else, like the code below?

1. #property copyright "Daniel Jose"
2. //+------------------------------------------------------------------+
3. void OnStart(void)
4. {
5.     Print("Result: ", 10 + 5);
6. }
7. //+------------------------------------------------------------------+

Code 04

Well, in some cases programming something like code 04 is actually the easiest way, since we are dealing exclusively with constants. However, this approach is not always desirable. This happens because numerical constants are "cold" and carry no information about why they exist. Looking at code 04, could you tell the reason for using the values 10 and 5? Perhaps we perform some factorization to discover an initially unknown result. If this were the case, we would use a different type of variable, which we will discuss in detail in another article. However, if this were not the case, we would eventually wonder why such a calculation is being performed, and we might end up having difficulty understanding our own code.

It is for this reason that many programmers utilize certain resources of the programming language they use. In this case (when we are just starting to talk about this topic and therefore explain how to program more efficiently), using variables is the best choice at this point. This is because we can give a variable a suitable name and even after a long time we will be able to understand the purpose of this value, even if the variable was implemented as a constant.

I believe the first point has been explained properly. The reader can now understand why in some cases we say that a variable is constant and in others not, and also what such a declaration does to our favorite variables. We will have another opportunity to talk about this topic, so we can now move on to another aspect without going beyond the basic concepts of variables.


Lifetime and visibility

One of the questions that often baffles even experienced programmers is the lifetime of variables, as well as their visibility scope. Although these two questions appear to be different, they can be considered together because lifetime and visibility are in some sense related. Visibility is a much broader topic, and we will cover it in more detail in other articles over time, as there are visibility issues that greatly impact how an application should be designed. We will sort this out in due time.

For now, we will focus on the most important thing: when a variable is "born", where it "dies" and whether its "death" can be prevented.

Not to complicate things, let's make some considerations. The first and the simplest one is as follows:

A variable is born at the moment it is declared..

This statement seems obvious, but things get a little more confusing when you look at it from the perspective of the variable visibility. Before we delve into this topic, let's look at a simple case. For this we use the following code.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     const int value1 = 10;
07.     int value2;
08. 
09.     value2 = 5;
10.     {
11.         int value2;
12. 
13.         value2 = 8;
14. 
15.         Print("Result #01: ", value1 + value2);
16.     }
17.     Print("Result #02: ", value1 + value2);
18. }
19. //+------------------------------------------------------------------+

Code 05

Before executing code 05, could you answer what value will be printed to the terminal when lines 15 and 17 are executed? Will this code not even compile? Before you start doubting, yes, this code will compile and run. However, there is one point here that you must understand. This is the first of several things you will come to understand as you go along this journey.

When code 05 is executed, you will see the result as shown in the image below.


Figure 07

Now I ask you again: Do you understand these results? This is just a small demonstration of what we can really do. Many programmers, even fairly experienced ones, avoid assigning variables the same name in the same block of code. But here we use not one block of code, but two. But how is this possible? Do we really have two blocks of code here in code 05? Dear reader, I have not lost my mind yet. The point is that we have only touched on a topic that will become clear another time. But in MQL5, as in other C and C++-like languages, each code block starts with an opening bracket `{` and ends with a closing bracket `}`.

Everything between these two characters is and should be considered a block of code. There are also other ways to define a block of code, such as loops. However, this option, using keys, is the easiest to understand. So, in this code, the block starts in line five and ends in line eighteen. Another block goes from the tenth to the sixteenth line. By understanding this we can cover two matters at once.

The first is the fact that a variable declared in code begins its "life" at the moment of declaration and ends its life at the moment when the block to which it belongs ceases to exist. There can be an exception, but don't worry about it yet. Just try to understand this simple concept that we are dealing with now. The second point is that anything declared outside a block will be considered as global from within the block.

This second aspect is a little more difficult to understand, but let's break it down step by step. First, let's look at why code 05 generates the output shown in image 07. From the above declarations, you can see that lines 7 and 11 declare a variable with the same name. In lines 9 and 13 we assign different values to a variable that in theory appears to be the same. However, if you pay attention to the code, you can see that they are in different blocks: one in one block, and the other in a block located inside the first one.

Simply put, the block where we declare value2 in line 7 is global. Therefore, value2 declared in line 7 is a global variable. In turn, the variable value2, declared in the eleventh line, is a local variable. When viewed from outside the block, the variable in line eleven is local; but within the block that begins in line ten, the variable declared in line eleven is considered global in that context.

I know this can be confusing, so let's stop for a moment and think about it. Understanding this concept is extremely important because we are not forced to use different names all the time. The compiler requires us to use different names for variables in the same block, but if the variables are in different blocks, the compiler will assume that they are different variables having the same names.

Then why do we get two different values in the end result? The reason is simple: a local variable will take precedence over a global variable if they both have the same name, regardless of the variable's type. If the name is identical, the compiler will prefer to use the local variable. But be careful, as some other languages may use different techniques. What we have seen here is specific to MQL5, as we have focused on this language.

So it's easy to understand the following fact: when we say in line thirteen that value2 is 8, it will not remove the value that value2 has in the global scope, which is 5 and was defined in line nine. For this reason, when we use line 15 to print the result of adding value1 to value2, in the first case we get 18. When line 17 performs the same calculation, the result will be 15.

However, if you try to do something similar using the following code:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     const int value1 = 10;
07.     int value2;
08. 
09.     value2 = 5;
10. 
11.         int value2;
12. 
13.         value2 = 8;
14. 
15.         Print("Result #01: ", value1 + value2);
16. 
17.     Print("Result #02: ", value1 + value2);
18. }
19. //+------------------------------------------------------------------+

Code 06

the compiler will complain and generate something similar Figure 08 below.


Figure 08

This is because, unlike code 05, code 06 consists of one block that starts in line 5 and ends in line 18. So be careful when you write code or try to understand what another programmer wrote and why your attempts to change the code failed.

However, you may encounter a slightly different situation. An example can be seen in the code below.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. int value2;
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     const int value1 = 10;
09. 
10.     value2 = 5;
11. 
12.         int value2;
13. 
14.         value2 = 8;
15. 
16.         Print("Result #01: ", value1 + value2);
17. 
18.     Print("Result #02: ", value1 + value2);
19. }
20. //+------------------------------------------------------------------+

Code 07

In this case, the compiler will output a message very similar to the one seen in Figure 09.


Figure 09

Looking at this message shown in image 09, what action should be taken regarding code 07 if our goal is to get a result similar to that shown in image 07? Dear readers, the moment has come when everything becomes much more complicated. The reason is that the value2 declaration made in line 4 will only "die" when the application ceases to exist or stops running. For this reason, in such cases, you CANNOT use variables with local scope together with variables with the same name that have global scope.

Generally, global variables or values themselves are a problem that should be avoided at all costs. This is not always possible, but if such a situation arises or there is no other alternative, you should use different names for variables. Many programmers, including myself, often add a prefix or suffix to distinguish global variables, which will exist for the life of the program, from local or even global variables, which belong to a specific block.


Final considerations

The first article has come to an end. In this article, I tried to explain to you, whether you are a beginner or a casual programmer, how to work with MQL5 more correctly and productively. The purpose of this article is to share with you a piece of my experience as a professional programmer, to show you how to start creating your own codes easily, effectively and without unnecessary hassle.

Programming is something beautiful and unforgettable. With the right approach and having a solid and consistent knowledge, it will definitely bring you good results in the future. So in the next article, we will continue to deal with variables, since here I have only presented the methodology that we will use in the following texts. I hope you enjoyed it. If you want to get acquainted with more complex material, yet with a similar methodology, you can read my other articles, available in this community, though published under a different profile.


Translated from Portuguese by MetaQuotes Ltd.
Original article: https://www.mql5.com/pt/articles/15301

Attached files |
Anexo.zip (0.73 KB)
Price Action Analysis Toolkit Development (Part 9): External Flow Price Action Analysis Toolkit Development (Part 9): External Flow
This article explores a new dimension of analysis using external libraries specifically designed for advanced analytics. These libraries, like pandas, provide powerful tools for processing and interpreting complex data, enabling traders to gain more profound insights into market dynamics. By integrating such technologies, we can bridge the gap between raw data and actionable strategies. Join us as we lay the foundation for this innovative approach and unlock the potential of combining technology with trading expertise.
Monitoring trading with push notifications — example of a MetaTrader 5 service Monitoring trading with push notifications — example of a MetaTrader 5 service
In this article, we will look at creating a service app for sending notifications to a smartphone about trading results. We will learn how to handle lists of Standard Library objects to organize a selection of objects by required properties.
Redefining MQL5 and MetaTrader 5 Indicators Redefining MQL5 and MetaTrader 5 Indicators
An innovative approach to collecting indicator information in MQL5 enables more flexible and streamlined data analysis by allowing developers to pass custom inputs to indicators for immediate calculations. This approach is particularly useful for algorithmic trading, as it provides enhanced control over the information processed by indicators, moving beyond traditional constraints.
Master MQL5 from Beginner to Pro (Part III): Complex Data Types and Include Files Master MQL5 from Beginner to Pro (Part III): Complex Data Types and Include Files
This is the third article in a series describing the main aspects of MQL5 programming. This article covers complex data types that were not discussed in the previous article. These include structures, unions, classes, and the 'function' data type. It also explains how to add modularity to your program using the #include preprocessor directive.