When an EA starts to get fairly large, structuring the code gets vital.
Ways to structure.
- Subroutines in main code
- Include subroutines as mqh
- Include classes
I have favoured Libraries. You get a clean interface and good "isolation".
During development it is a bit of a overhead compared to "inline" subroutines.
I have also used straight include of subroutines. It cleans up the main code and gives a better overview
I do not see the benefits of using classes except for more complex functions. I have had a few cases where I found it beneficial to use it
Talking about libraries.
Libraries can actually be seen as Objects. You can store data, retrieve data and store code that manipulate the data as with objects
set data, retrive data and manipulate data. Properties and methods. Quite useful.
Why do you need opinions ?
You have the right approach, just use what you find appropriate for you and don't care about other opinions.
A fact not well know is that using MQL libraries (EX4 libraries) for separating large codes is one of the worst ideas one can have. Even MetaQuotes admits this in the first MQL help files. They are slower than any other solution (including DLL calls), limited (you can't pass direct pointers between modules) and surprise with all kind of internal errors.
This is related to their nature. A regular MQL executable is loaded into memory and unloaded after use. However under certain circumstances a library can stay in memory and doesn't get unloaded. This can cause nice surprises e.g. in Tester when you start a new test and the library still holds runtime data from a former test because it wasn't unloaded.
Or you stop an expert, recompile and reload it and the library (which stayed in memory) continues to return TRUE for IsStopped().
Whenever you can replace libraries with something else. You safe yourself some headaches.
Sounds strange to me that Metaquotes just leaves it like that. Or have they fixed it in MQL5?
I have been using libraries for years both in MQL4 and MQL5 and for various functions and never seen any problems where I can point a finger at the library.
I have done some extensive searches on the net trying to find any information about problems with MQL4 Libraries.
Nada, zero, null, zilch
Before I take your recommendation you will have to substantiate your claim that libraries are bad in the meaning that they do not work as they are meant to work
A fact not well know is that using MQL libraries (EX4 libraries) for separating large codes is one of the worst ideas one can have. Even MetaQuotes admits this in the first MQL help files.
Can you give more information (specific links and/or metrics)?
Like @Ingvar Engelbrecht states, I have been using MQL libraries for MQL5 and haven't noticed any issues related to this.
Well, I can't say which of the bugs are fixed in MQL5 as I don't use it. There are enough tickets at the Service Desk which got labelled "won't fix" as the fix requires major rewrites of parts of the terminal. Maybe all of you can help here with testing.Btw: A MQL library also executes the regular OnInit() and OnDeinit() functions if they are implemented. With this functions one can see if/when the library is loaded/unloaded.
- As for speed that's the smallest issue and everybody can test it by himself. Write a simple function adding two numbers in a library and in an include file and measure the execution time of a few 1000s calls.
- IsStopped() as already explained. How to reproduce: Write a library function that logs the flag and call it from an expert. Now open the expert in MetaEditor and recompile it. The editor will signal to the terminal to reload the recompiled expert. Call the library function again after reloading.- IsVisualMode() is not updated between consecutive tests. It continues to return the status of the first call. How to reproduce: Write a library function that logs the flag. Run a test and call the function in the test. Stop the test, toggle the "Visual" check box and immediately start a new test. Call the function again. Workaround: I had to write a function that pulls the visual flag from the main MQL module.- order context: Each MQL module has it's own active order context (you can't select a ticket in one module and call the order functions in another module). In the tester the order context of a library is not reset if the library is not reloaded. You can even change symbol or timeframe under test and the order context of the new test is still initialized with the old data. Workaround: Explicitely reset the order context in library::OnInit() to 0 (zero) and suppress an error.- static vars: Static variables must always be initialized explicitely. With implicit initialization they keep their values between consecutive tests and are not reset. Workaround: Reset library arrays explicitely in library:OnInit()In general most issues arise in relation to the tester and the way the test environment is (re-)initialized between tests. For example one could argue that the behaviour regarding static variables is correct. However, the behaviour of the runtime environment is not correct as we can expect a clean environment on test start. No matter what the internal implementation details of the terminal or the language specifics looks like. It can't be that we start a test and are confronted with data from an old one.
Then there is another not well-known feature which makes it hard to spot things like above: The error handling.
Each module has its own error context. There is no regular way to inform the MQL main module about errors in a submodule (library or loaded/instantiated indicator). Here I'm not talking about function return values but about error conditions happening outside of regular function flow. With the existing tools they are almost not to detect and I still have to see a single source in the code base or elsewhere with properly implemented error handling.
All of this was reason enough for me to stick longer than planned to MQL4 as there I have all the tools missing, including complete error handling and full module-to-module communication in both directions. Now I would be happy to hear that all of the above issues are finally fixed in MQL5.