Did Structs Change with the last MT5 Update? - page 5

 
Alain Verleyen #:

Multi-inheritance was approved then stopped years ago already (it's somewhere on the forum). I don't think it will ever be implemented. It's a pity as it prevents to code very interesting patterns like 'Policy based design'.


I agree, multiple inheritance is a powerful abstraction tool. One use case is to separate out data from logic.


 
Doerk Hilger #:

You only end up with it when you use both: this= in the assignment function and overloading the operator.
And yes. This might not be a big deal with 2-4 fields, but with structs that have 50+ fields, the chance for human mistakes and other bugs is way higher then.  
Besides this, you can also send a struct to a DLL function and do the copy job there, without any conversion to CharArray, if you like that better. 


A struct with so much memory use points to a design flaw, IMHO.

There is no benefit in such a struct. No memory alignment, no cache alignment, no optimized data selection on use case.

At that point you are almost better off using an in-memory SQL db.

Anyways, assignment via "this=" seems a solution to a problem that can't be fixed: liability by written code.

EDIT:

The advantage of a struct is actually the implicit copy and assignment operator provided by the compiler. Maybe there is a possible solution to utilize the compilers ability to aid your needs.
 
Dominik Egert #:

A struct with so much memory use points to a design flaw, IMHO.

There is no benefit in such a struct. No memory alignment, no cache alignment, no optimized data selection on use case.

At that point you are almost better off using an in-memory SQL db.

Anyways, assignment via "this=" seems a solution to a problem that can't be fixed: liability by written code.

EDIT:

The advantage of a struct is actually the implicit copy and assignment operator provided by the compiler. Maybe there is a possible solution to utilize the compilers ability to aid your needs.

Thanks for your reply.

The thing is, the signal flow of how we work with MQL has not much to do with usual MQL-coding and thats why your arguments, valid in a normal case, don´t have weight here.

I´ve developed an stable and fast IPC which allows me to do sync and async communication between MQL and C#, forth AND back at a speed which is at factor 3-5 im comparison to NamedPipes (15-20 µs per synced roundtrip). Both, MQL side and C# side provide a server and act as peers. From C# I can request data from MQL and it responds either in string messages or returns or sends data blocks in structs, which I can read or write in C# without any copies in between. Vice versa, from MQL to C# anyway. Tickdata, bars, tradedata, colorsschemes, metrics, statistics etc. is all organized in structs, and both sides access them kinda directly and both sides have a similar or identical set of struct-functions. This gives me the opportunity to use C# mainly for coding in the meanwhile. Not only that, EAs, indicators, services, everyone communicates with everyone frequently, and it all uses the same structs. 

The overhead with a database would be a bottleneck, since it would be managed by one further server within one single thread, would create even more data-copies on the heap and would require a further, mutual local mutex - another bottleneck. 

This IPC based architecture doesn´t even require me to work with DLLs all the time, actually there is just the IPC itself which needs a DLL, but all the rest is done by multiple service applications in C#, and we can even debug easily in C# and edit code while debugging. 

I think you understand it a little better from this viewpoint. 

 
Doerk Hilger #:

Thanks for your reply.

The thing is, the signal flow of how we work with MQL has not much to do with usual MQL-coding and thats why your arguments, valid in a normal case, don´t have weight here.

I´ve developed an stable and fast IPC which allows me to do sync and async communication between MQL and C#, forth AND back at a speed which is at factor 3-5 im comparison to NamedPipes (15-20 µs per synced roundtrip). Both, MQL side and C# side provide a server and act as peers. From C# I can request data from MQL and it responds either in string messages or returns or sends data blocks in structs, which I can read or write in C# without any copies in between. Vice versa, from MQL to C# anyway. Tickdata, bars, tradedata, colorsschemes, metrics, statistics etc. is all organized in structs, and both sides access them kinda directly and both sides have a similar or identical set of struct-functions. This gives me the opportunity to use C# mainly for coding in the meanwhile. Not only that, EAs, indicators, services, everyone communicates with everyone frequently, and it all uses the same structs. 

The overhead with a database would be a bottleneck, since it would be managed by one further server within one single thread, would create even more data-copies on the heap and would require a further, mutual local mutex - another bottleneck. 

This IPC based architecture doesn´t even require me to work with DLLs all the time, actually there is just the IPC itself which needs a DLL, but all the rest is done by multiple service applications in C#, and we can even debug easily in C# and edit code while debugging. 

I think you understand it a little better from this viewpoint. 

Well, thank you for this insight. - There is no argument against what I said. Also, SqLite is a threadless database >file< which handles all requests form external programs inside the file itseslf. - There is no such thing as a thread, except the ones you use to access the file.

Also, I cannot see how a struct with so many variables can be a sign of a good data-design. 

As an example, if you want to take a look, I have attached a file with a bad design. - If this were actually properly designed, it would use inheritance to solve the generalized access method used.

So, basically, "this=" is not a proper way to do it, if coding within a language that is much like C/C++. So my argument is still, you have a bad design for your data. Also, your design requires you to maintain for both languages C# and MQL a header file for each structure you use. So, you are stuck with >liability of written code<. 

If speed of IPC is so important to your project, then you will need to redesign your data handling. Or you are trying to overcompensate an issue, that is actually not an issue. 

Not trying to be rude here, but facts seem obvious.


EDIT: 

Your website should ask for cookie consent.

Files:
 
Dominik Egert #:
Well, thank you for this insight. - There is no argument against what I said. Also, SqLite is a threadless database >file< which handles all requests form external programs inside the file itseslf. - There is no such thing as a thread, except the ones you use to access the file.

Exactly. And since all the data from no matter which part of your code is stored in the same memory region, every access from every client blocks the other. Thats not an option when you deal with multiple threads, not in view of speed and not in view of saftey. Like you said, there is not one thread, which is also not necessarily true since indexing can occur in a separate one, there are the client threads and they need share one mutual mutex. And that is a massive problem when you need throughput more than anything else. 


>>So, basically, "this=" is not a proper way to do it, if coding within a language that is much like C/C++. <<

When you develop IPC, you work low level. Like described earlier: this= , in case of doubts, will be compiled to "rep movsd", 4 lines of assembler code vs 200 lines when you have 50 fields. Which is also a matter of thread safety by the way. 

>> So my argument is still, you have a bad design for your data.<<

Change your perspective. 

>> If speed of IPC is so important to your project, then you will need to redesign your data handling. Or you are trying to overcompensate an issue, that is actually not an issue. <<

Open 20-30-40 charts within 3-4 MT instances same time, copy all ticks and all bars in realtime when news like NFPs come up via IPC to one or more foreign processes. Then you will see what happens: Candles wont move anymore in every chart. And this starts already much earlier with way less pressure. How do I know? I did it before and had this bottleneck, and this was not even a SQL database, it was one mutex for one MMF, also low-level. 

Our stuff has to work on every crappy VPS, and the user wont judge the product by the way we organized variables in structs, they will judge it based on how it "feels" for them: Heavy or light.  

Edit: W
hat is "good design"?

It is related to your perspective, there is never one absolute truth. My way of doing this has the risk, that nothing works anymore, whenever MQ changes the way they store data within structs, I know that and I take that risk. And when following "good standards", you have the risk of losing performance. I know that too but I decided to rather take risk number #1. I come from Assembler originally, for me its ok to have these low level coding risks. Performance matters the most for me. 

 
Doerk Hilger #:

Exactly. And since all the data from no matter which part of your code is stored in the same memory region, every access from every client blocks the other. Thats not an option when you deal with multiple threads, not in view of speed and not in view of saftey. Like you said, there is not one thread, which is also not necessarily true since indexing can occur in a separate one, there are the client threads and they need share one mutual mutex. And that is a massive problem when you need throughput more than anything else. 


>>So, basically, "this=" is not a proper way to do it, if coding within a language that is much like C/C++. <<

When you develop IPC, you work low level. Like described earlier: this= , in case of doubts, will be compiled to "rep movsd", 4 lines of assembler code vs 200 lines when you have 50 fields. Which is also a matter of thread safety by the way. 

>> So my argument is still, you have a bad design for your data.<<

Change your perspective. 

>> If speed of IPC is so important to your project, then you will need to redesign your data handling. Or you are trying to overcompensate an issue, that is actually not an issue. <<

Open 20-30-40 charts within 3-4 MT instances same time, copy all ticks and all bars in realtime when news like NFPs come up via IPC to one or more foreign processes. Then you will see what happens: Candles wont move anymore in every chart. And this starts already much earlier with way less pressure. How do I know? I did it before and had this bottleneck, and this was not even a SQL database, it was one mutex for one MMF, also low-level. 

Our stuff has to work on every crappy VPS, and the user wont judge the product by the way we organized variables in structs, they will judge it based on how it "feels" for them: Heavy or light.  

Edit: W
hat is "good design"?

It is related to your perspective, there is never one absolute truth. My way of doing this has the risk, that nothing works anymore, whenever MQ changes the way they store data within structs, I know that and I take that risk. And when following "good standards", you have the risk of losing performance. I know that too but I decided to rather take risk number #1. I come from Assembler originally, for me its ok to have these low level coding risks. Performance matters the most for me. 


Aha. So you are right and there is no solution to your problem, right?

So basically you are telling me, its not the software, not your design, and not the concept that's the problem, did I get that right?

So then there are only two options left, as far as I can see: option one: I am the problem. Option two: you are the problem.

But for sure its not the design of your software that's the problem, though its the only thing (next to yourself) that's in your control...

I wonder if you are doing this to entertain yourself, or to harvest some validation.

Want to put up a bet? A bet, that I know 4 people here on the forum who can solve your problem, actually, permanently. - Would you bet on it being right, or will this just be one of those rambling, incoherent chats/threads, we have seen over the years?

I remember a discussion with you around build 27xx, where you weren't able to update. I offered my support, did you take it? - Obviously not, else you wouldn't be complaining again.
 
Dominik Egert #:

Aha. So you are right and there is no solution to your problem, right?

So basically you are telling me, its not the software, not your design, and not the concept that's the problem, did I get that right?

So then there are only two options left, as far as I can see: option one: I am the problem. Option two: you are the problem.

But for sure its not the design of your software that's the problem, though its the only thing (next to yourself) that's in your control...

I wonder if you are doing this to entertain yourself, or to harvest some validation.

Want to put up a bet? A bet, that I know 4 people here on the forum who can solve your problem, actually, permanently. - Would you bet on it being right, or will this just be one of those rambling, incoherent chats/threads, we have seen over the years?

I remember a discussion with you around build 27xx, where you weren't able to update. I offered my support, did you take it? - Obviously not, else you wouldn't be complaining again.

Which problem? There is no problem.

Originally, I just pointed out an easy shortcut for handling structs with many fields ( this= ). Since then, I’ve been lectured about ‘bad design,’ as if there were some universal truth valid for every use case.

I politely explained that my criteria are different and my use case is entirely another. But apparently, being right matters more – so now you bring up four other people who don’t share my use case either, just to ‘prove’ I’m wrong? :D

Meanwhile, the result is an IPC that outperforms NamedPipes by a factor of 3 and even allows MQL to act as a stable server - based on "bad design". I don’t know of any other working solution that can do that, otherwise I wouldn´t have developed it. Years ago someone here tried with NamedPipes, but ran into issues and couldn’t finish. If you dig deeper, you’ll realize the real bottleneck is MQL’s single thread – that’s why you must never use semaphores, mutexes, or WaitOne() directly in MQL. If execution stalls, you’ll be rebooting your machine every time.

I don’t want to bet – we’re not in a casino here. But if you can show me a safer way with comparable performance, feel free. If it’s useful for our or other use cases, you’ll even make money with it. No need for gambling

 
Doerk Hilger #:

Which problem? There is no problem.

Originally, I just pointed out an easy shortcut for handling structs with many fields ( this= ). Since then, I’ve been lectured about ‘bad design,’ as if there were some universal truth valid for every use case.

I politely explained that my criteria are different and my use case is entirely another. But apparently, being right matters more – so now you bring up four other people who don’t share my use case either, just to ‘prove’ I’m wrong? :D

Meanwhile, the result is an IPC that outperforms NamedPipes by a factor of 3 and even allows MQL to act as a stable server - based on "bad design". I don’t know of any other working solution that can do that, otherwise I wouldn´t have developed it. Years ago someone here tried with NamedPipes, but ran into issues and couldn’t finish. If you dig deeper, you’ll realize the real bottleneck is MQL’s single thread – that’s why you must never use semaphores, mutexes, or WaitOne() directly in MQL. If execution stalls, you’ll be rebooting your machine every time.

I don’t want to bet – we’re not in a casino here. But if you can show me a safer way with comparable performance, feel free. If it’s useful for our or other use cases, you’ll even make money with it. No need for gambling

IPC via shared memory, non-blocking, threadsave read-write.

Use a dynamic ring buffer, one for read, one for write per client connection/writer thread.

EDIT: and since you are moving a lot of data use a dedicated payload area.

EDIT2: use protobuf library/protocol to partition your payload, then you dont even need the oversized structs anymore.

EDIT3: this method uses only atomic/non-blocking updates to the ring buffer. It will always be at the edge of what's pushable by the CPUs involved.

Next would be to manage cache locality on the cores. I bet you, this can go to hundreds of gigabytes per second, just on the IPC.

EDIT4: a smartly implemented ring buffer should be doable in the picoseconds range, somewhat around maybe 10 to 20 CPU instructions, at worst. Probably much better possible. IE when limiting the size of the ring buffer to a pow of 2, you can use a mask and a natural overflow/rollover.
 
Dominik Egert #:
IPC via shared memory, non-blocking, threadsave read-write.

Use a dynamic ring buffer, one for read, one for write per client connection.

The problem is: Everyone has access to ChatGPT and when you ask it, how to, it comes always with ring-buffer and that stuff. I can ensure you upfront: Its not what will work and also not what you wanna manage later. You will also figure out: Its not what you need, since you update the most of the time, not request.

Anyway, I assume you just talk about theory and have not yet developed such a thing. Correct me if I am wrong. 

 
Nonetheless, this is getting offtopic. How bout you open a new thread and show us how you wanna do it. And dont forget: We talk about a server in MQL, not in C#. Your main question should be first: How to feed, to receive and how to avoid blocking. 

>>EDIT3: this method uses only atomic/non-blocking updates to the ring buffer. It will always be at the edge of what's pushable by the CPUs involved.<< will not work in multithreading environment. 
 
Doerk Hilger #:

The problem is: Everyone has access to ChatGPT and when you ask it, how to, it comes always with ring-buffer and that stuff. I can ensure you upfront: Its not what will work and also not what you wanna manage later. 
Nonetheless, this is getting offtopic. How bout you open a new thread and show us how you wanna do it. And dont forget: We talk about a server in MQL, not in C#.  

>>EDIT3: this method uses only atomic/non-blocking updates to the ring buffer. It will always be at the edge of what's pushable by the CPUs involved.<< will not work in multithreading environment. 
Thank you for the confirmation. - You are not interested in a solution, as it seems. I gave you the solution that runs on NYST. But its fine, how could I know, after all, you solved it already. - Or are you just trying to escape payment? :-)