Questions on OOP in MQL5 - page 46

 
Igor Makanu:

that's exactly what I got away from, and that's what I did at first

with this approach - to inherit from a base class, "where everything is" - everything works, but until we want to try making several class fields, and then we want to add more fields in each field-class, and nail it all with a dynamic array of classes

and then we'll get that we can't implement the Save(int hndl) method itself in a base class - this method will actually be an interface, which, as discussed above, won't be needed at all - you can write it without interfaces

i usually maximize my efforts on code flexibility - minimum fuss - result is a new problem solved, may my terminology be forgiven)))


the problem will be, when implementing saving to file, you need towork out the file header, which should describe the total amount of different types of entries. Then you need to work out the logic / order of data saving, in order to read everything correctly.... and the finale will be if you change even one field in one class

imho, the laboriousness of such "easy" inheritance from a base class - comes down to development and maintenance of a small database, constant monitoring of changes in any class

public:
 void CBase::Save(...){
    SaveHeard(...);
    _Save(...)}
virtual void SaveHeard(...){...}

protected:
   void _Save(...){
       CBase::_Save(...);
       ...}

Something like this))))

 
Vladimir Simakov:

Something like this))))

I understand all this, but to the old saying "MQL is not C," you can only add that it makes no sense to rely on a well structured code by tasks - MQL tasks are always highly specialized and re-use of large code is often not effective.

HH: imho the main goal of MQL code is to be as fast as possible, to be used in the tester or to execute the code within one tick - without losing ticks, it's all clear, but there are some restrictions - you can't ignore the situation with connection breakdowns and PC / terminal reboot, and it's all about finding the optimum, not justa nice and structured code

 
Igor Makanu:

2. is there a hack to describe operator= , and use the native copy operator in it? .... i.e. some way to call : :=

there is a way, and as usual the solution is simple:

struct SMatrix
{
   struct SMATRIX{
   SMATRIX(){}
   struct SRow{int COL[];};
   SRow ROW[];
   };
   SMATRIX MATRIX;
   SMatrix(){}
   SMatrix(const int rows,const int cols){ this.Resize(rows,cols); }
   void Resize(const int rows,const int cols){ ArrayResize(this.MATRIX.ROW,rows); for(int i=0;i<rows; i++){ ArrayResize(this.MATRIX.ROW[i].COL,cols); }}
   void Free() { for(int i=0;i<ArraySize(this.MATRIX.ROW[i].COL); i++){ ArrayFree(this.MATRIX.ROW[i].COL); } ArrayFree(this.MATRIX.ROW);}
   int RowCount()const { return(ArraySize(this.MATRIX.ROW)); }
   int ColCount()const { if(this.RowCount()>0) return(ArraySize(this.MATRIX.ROW[0].COL)); else return(0); }
   void operator=(const SMatrix &v) { this.Resize(v.RowCount(),v.ColCount()); this.MATRIX = v.MATRIX;}

};

//+------------------------------------------------------------------+
void OnStart()
{
   SMatrix A(2, 5);
   int count = 0;
   for(int i = 0; i < A.RowCount(); i++)
      for(int j = 0; j < A.ColCount(); j++)
         A.MATRIX.ROW[i].COL[j] = count++;
   
   SMatrix C(5, 2);
   count = 100;
   for(int i = 0; i < C.RowCount(); i++)
      for(int j = 0; j < C.ColCount(); j++)
         C.MATRIX.ROW[i].COL[j] = count++;

   
   SMatrix B = A;
   for(int i = 0; i < B.RowCount(); i++)
      ArrayPrint(B.MATRIX.ROW[i].COL);
   
   B = C;
   for(int i = 0; i < B.RowCount(); i++)
      ArrayPrint(B.MATRIX.ROW[i].COL);
   
}

we initialize matrix A, then C

we first assign a new matrix B = A and uninitialize , then B = C and uninitialize

2020.04.21 00:35:50.559 tst (EURUSD,H1) 0 1 2 3 4

2020.04.21 00:35:50.559 tst (EURUSD,H1) 5 6 7 8 9

2020.04.21 00:35:50.560 tst (EURUSD,H1) 100 101

2020.04.21 00:35:50.560 tst (EURUSD,H1) 102 103

2020.04.21 00:35:50.560 tst (EURUSD,H1) 104 105

2020.04.21 00:35:50.560 tst (EURUSD,H1) 106 107

2020.04.21 00:35:50.560 tst (EURUSD,H1) 108 109

the point - you need to wrap the structure into the structure and again into the structure.... excuse my technical term ))))


SZY: solution is good, we should replace RowCount() and ColCount() methods by RowCount and ColCount() structure fields, to make less calls... But on the whole, it works as I wanted it to

 
Are you serious?
 
Алексей Тарабанов:
Are you serious?

What's the big deal, the man has been solving this problem since 2012, don't bother him, he knows best.

 
Sergey Dzyublik:

What's the big deal, the man has been solving this problem since 2012, don't bother him, he knows best.

You are thinking flat.

the task is to know the technical capabilities of the MQL language, so that such an examplehttps://docs.microsoft.com/en-us/archive/msdn-magazine/2018/april/test-run-understanding-lstm-cells-using-csharp

can be ported "directly" - this task has been solved now, porting all functions of the example one-to-one with one assumption: float[][] result --> SMatrix result

 
Igor Makanu:

there is a way, and as usual the solution is simple:

initialize matrix A, then C

first assign a new matrix B = A and uninitialize , then B = C and uninitialize


HH: solution is good, we need to replace RowCount() and ColCount() methods by RowCount and ColCount() structure fields to make fewer calls ... But on the whole, everything works as I wanted it to.

Unfortunately, not everything is as happy as we would have liked. In MQL, there is a longstanding bug with array copying by the default copy operator. It is only ArrayCopy of elements from one array into another that occurs. The size of the resulting array is not synchronized with the source (it's not truncated). It means, if A(10) and B(20) were used, after B=A you'll get B(20) as well, i.e. half of the elements will be replaced with items from A, the rest will remain the same. This, of course, is not at all what you expect from the= operator. That's why we'll have to write our own operator for arrays.

I must admit that I thought this bug had been already fixed. But I checked it and it's still there.

 
Alexey Navoykov:

Unfortunately, not everything is as happy as we would like it to be. MQL has a long-standing bug with array copying using the default copy operator. Only ArrayCopy of elements from one array to another occurs. The size of the resulting array is not synchronized with the source (it's not truncated). It means, if A(10) and B(20) were used, after B=A you'll get B(20) as well, i.e. half of the elements will be replaced with items from A, the rest will remain the same. This, of course, is not at all what you expect from the= operator. That's why we'll have to write our own operator for arrays.

I must confess that I thought this bug had been already fixed. But I checked it and it is still there.

The bug was recently recalled:

Forum on Trading, Automated Trading Systems and Strategy Testing

OOP questions in MQL5

Sergey Dzyublik, 2020.04.18 17:48

Then, according to your terminology, calling the default assignment operator may give "incomplete data type".
Bug from 2019.05.03 never fixed:https://www.mql5.com/ru/forum/1111/page2451#comment_11556395


The given line is supposed to bypass the bug:

struct SMatrix
{
   struct SMATRIX{
   SMATRIX(){}
   struct SRow{int COL[];};
   SRow ROW[];
   };
   SMATRIX MATRIX;
   SMatrix(){}
   SMatrix(const int rows,const int cols){ this.Resize(rows,cols); }
   void Resize(const int rows,const int cols){ ArrayResize(this.MATRIX.ROW,rows); for(int i=0;i<rows; i++){ ArrayResize(this.MATRIX.ROW[i].COL,cols); }}
   void Free() { for(int i=0;i<ArraySize(this.MATRIX.ROW[i].COL); i++){ ArrayFree(this.MATRIX.ROW[i].COL); } ArrayFree(this.MATRIX.ROW);}
   int RowCount()const { return(ArraySize(this.MATRIX.ROW)); }
   int ColCount()const { if(this.RowCount()>0) return(ArraySize(this.MATRIX.ROW[0].COL)); else return(0); }
   void operator=(const SMatrix &v) { this.Resize(v.RowCount(),v.ColCount()); this.MATRIX = v.MATRIX;}

};
 
Sergey Dzyublik:

The given line should bypass the bug:

Oh, yeah, I didn't notice it at first... But then you could have written ArrayCopy right away. Why do we need this SMATRIX gasket at all then?..

 
Alexey Navoykov:

Oh, yeah, I didn't notice it at first... But then you could have written ArrayCopy right away. Why do we need this SMATRIX pad at all?...

МТ developers always write that using built-in compiler mechanisms will be faster even than calling standard functions

If you have time and interest, check the speed of my version and yours with ArrayCopy

I'll check the speed a bit later, I'm in the middle of a lesson