Return Struct When Struct has Constructor

 

The goal is to, have a function getTradeRecord that returns a struct trade_record.  That struct should be initialized by its constructor.


The problem is, when the struct trade_record is initialized by its constructor, we get a compilation error in the return statement.


Code bellow:

//+------------------------------------------------------------------+
//|                                                   TestStruct.mq5 |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }


struct trade_record
  {
   double            sl;
   double            tp;
   double            longVolume;
   double            shortVolume;
   bool              issue;
   string            message;

                     trade_record(double _sl, double _tp)
     {
      this.sl = _sl;
      this.tp = _tp;
     };
  };
  
trade_record getTradeRecord()
{
   trade_record result(10, 10);  
   
   return result;
}


//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//---

   // trade_record record = getTradeRecord();

//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+


Image of the compilation error bellow follow as an attachment.


Is this a issue with the language, or I'm missing something?


Are there a more idiomatic why of doing this? Could someone provide some guidance in returning a record type from a function.

Files:
 

Here is one way to do it - the benefit is you can also call the trade_record_Init() function directly too, later with new arguments if the values need to be changed

struct trade_record
  {
   double            sl;
   double            tp;
   double            longVolume;
   double            shortVolume;
   bool              issue;
   string            message;

                     trade_record() //constructor
     {
      this.trade_record_Init(10, 10);
     };


   void              trade_record_Init(double _sl, double _tp)
     {
      this.sl = _sl;
      this.tp = _tp;
     };

   trade_record      getTradeRecord()
     {
      trade_record result;
      return result;
     }

  };
 
The example above is faulty.

Reason is, constructors have not been understood.

In the OP, the constructor is a specific constructor. You are missing the default constructor and the copy constructor.

The example with a member function as an init function is out of scope of correct OOP.

You need to have default and copy constructor as well as an assignment operator for your feature to work correctly.


struct trade_record
  {
   double            sl;
   double            tp;
   double            longVolume;
   double            shortVolume;
   bool              issue;
   string            message;

     trade_record() :
         sl 		(NULL),
         tp 		(NULL),
         longVolume 	(NULL),
         shortVolume 	(NULL),
         issue 		(NULL),
         message 	(NULL)
     {};
     trade_record(const trade_record& p_in)
     { 
         sl 		= p_in.sl;
         tp		= p_in.tp;
	 longVolume	= p_in.longVolume;
	 shortVolume	= p_in.shortVolume;
	 issue		= p_in.issue;
	 message	= p_in.message;
     };
     trade_record(double _sl, double _tp)
     {
      this.sl = _sl;
      this.tp = _tp;
     };
     trade_record operator=(const trade_record& p_in)
     {
         sl 		= p_in.sl;
	 tp		= p_in.tp;
         longVolume	= p_in.longVolume;
	 shortVolume	= p_in.shortVolume;
	 issue		= p_in.issue;
	 message	= p_in.message;

         return(this);
     };
  };
  
 
Dominik Christian Egert #:
The example above is faulty.

Reason is, constructors have not been understood.

In the OP, the constructor is a specific constructor. You are missing the default constructor and the copy constructor.

The example with a member function as an init function is out of scope of correct OOP.

You need to have default and copy constructor as well as an assignment operator for your feature to work correctly.

You raise a good point about having other constructors - then the fix to the original code is easy, just adding 1 line to make a default constructor.

 

struct trade_record
  {
   double            sl;
   double            tp;
   double            longVolume;
   double            shortVolume;
   bool              issue;
   string            message;

                     trade_record() {}; //Default constructor fix added
                     trade_record(double _sl, double _tp) 
     {
      this.sl = _sl;
      this.tp = _tp;
     };
  };

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
trade_record getTradeRecord()
  {
   trade_record result(10, 10);

   return result;
  }
 
Your default constructor is flawed, see my example.

Anyways, you still need a copy constructor.

And you "need" an assignment operator.

Do not skip what I have posted. Be precise
 
Dominik Christian Egert #:
Your default constructor is flawed, see my example.

Anyways, you still need a copy constructor.

And you "need" an assignment operator.

Do not skip what I have posted. Be precise

I was precise - I compiled your code as shown below before responding and unlike mine, it does not work (but I decided to be polite and not mention that).

Of course I can fix your code too, but it is better you post working code in the first place - should we say OOPs? Just kidding of course.

My second post was to acknowledge you had thrown light on another (purist) way to solve this, read it as you will.


struct trade_record
  {
   double            sl;
   double            tp;
   double            longVolume;
   double            shortVolume;
   bool              issue;
   string            message;

     trade_record() :
         sl (NULL),
         tp (NULL),
         longVolume (NULL),
         shortVolume (NULL),
         issue (NULL),
         message (NULL),
     {};
     trade_record(const trade_record& p_in)
     { 
         sl = p_in.sl;
         [...]
     };
     trade_record(double _sl, double _tp)
     {
      this.sl = _sl;
      this.tp = _tp;
     };
     trade_record operator=(const trade_record& p_in)
     {
         sl = p_in.sl;
         [...]
         return(this);
     };
  };
 
Ok. Good.

But how is this supposed to compile??

I was lazy, indeed. So I spared typing all the variables...

I was expecting for a coder to be able to see this and fill the gap.

I usually do not give no brainer answers, although, sometimes I ask such questions.



     trade_record(const trade_record& p_in)
     { 
         sl = p_in.sl;
         [...]
     };
 
Dominik Christian Egert #:
Ok. Good.

But how is this supposed to compile??

I was lazy, indeed. So I spared typing all the variables...

I was expecting for a coder to be able to see this and fill the gap.

I usually do not give no brainer answers, although, sometimes I ask such questions.



You did say "Be precise" so why not follow your own advice?

And if we are being precise, have you observed that we are talking about a Struct and not an object? So where does that fit with your assertion about "scope of correct OOP"?


 
Well, ok, you got me on that.

What I meant when saying be precise, is the conceptual background.

Structures and classes are both objects, aren't they? As template, as interface, they belong to the basics of object oriented programming.

Both s tructures and classes are fundamental types and the basic building blocks of objects.

Both can be templated, and can inherit, as well as be managed as heap objects. Both support constructors and destructors, operators as well as access key words. Only classes have some more features, like virtual functions, Interfaces etc.

So, I do think it is fully legit to see structures and classes as part of OOP.

I would have probably typed all the code, and checked it, if I had not been posting on mobile.
Typing code on a phone is very inconvenient. So I spared it, due to inconvenience and lazyness.

But I already said that, and I personally think spoon feeding people with ready made solutions, disengages their thinking process on the matter. So, if the basic concept is correctly communicated, but there are some coding errors, it should not be to hard for anyone to fix it.

Anyways, when people only perform copy and paste, they do not learn from their question, but bypass the process of learning.

I accept your criticism about not being precise.


 
Dominik Christian Egert #:
Well, ok, you got me on that.

What I meant when saying be precise, is the conceptual background.

Structures and classes are both objects, aren't they? As template, as interface, they belong to the basics of object oriented programming.

Both s tructures and classes are fundamental types and the basic building blocks of objects.

Both can be templated, and can inherit, as well as be managed as heap objects. Both support constructors and destructors, operators as well as access key words. Only classes have some more features, like virtual functions, Interfaces etc.

So, I do think it is fully legit to see structures and classes as part of OOP.

I would have probably typed all the code, and checked it, if I had not been posting on mobile.
Typing code on a phone is very inconvenient. So I spared it, due to inconvenience and lazyness.

But I already said that, and I personally think spoon feeding people with ready made solutions, disengages their thinking process on the matter. So, if the basic concept is correctly communicated, but there are some coding errors, it should not be to hard for anyone to fix it.

Anyways, when people only perform copy and paste, they do not learn from their question, but bypass the process of learning.

I accept your criticism about not being precise.


Well let's not prolong this debate when the solution is evident.

I see your point about using constructors and appreciate you are passionate about best practice. I too like this, although perhaps I am less worried about compliance with specific design ideas and paradigms - I just want well written and efficient code, and as we see in this case, I also prefer the simplest/quickest/best solution to resolve a problem at hand (which your involvement lead to... so thanks)

I agree it is not good to spoon feed too much, but when someone asks for help, I believe one should at least post compilable, relevant and working code. It saves time for anyone who wants to compile and test it, rather than having to guess what the provider meant and reverse engineer it to make it work.

Have a good day! 

 
Yes, I will take your advice into consideration and raise the quality of my posted code.