OOP issue : idea to break a vicious circle ? - page 4

 
nicholi shen:

Easy-peazy. This is only possible because the data is structured. If you had something spitting out random bits of data on the other end then and the only way to make since of it is by inferring some value solely by type -- then it's time to refactor what is doing the serialization to begin with.  


I got the idea of key+value pairs, I just assume that if the data had some more properties other then type, Alain would have used that, because that makes the problem much easier. Maybe refactoring is needed, maybe there is a reason as to why this Is the case, I can't tell for sure.

 
nicholi shen:

What you are suggesting would be the equivalent to sending a mixed bag and praying the computing gods that nothing dangerous will happen (spoilers: it will). 

Thanks for giving me a mirror for the sattle ways you (I) can get personal without realising it. It is also true from the whole standpoint of your comment, trying to outsmart without having enough info, even though all that you said was clear from the beginning.
 
Amir Yacoby:

I got the idea of key+value pairs, I just assume that if the data had some more properties other then type, Alain would have used that, because that makes the problem much easier. Maybe refactoring is needed, maybe there is a reason as to why this Is the case, I can't tell for sure.

Thanks trying to help,when some are just trying to show how "smart" they are.

I give up this topic and probably this forum.

 
nicholi shen:

There's no need for ad hominem attacks, Alain. I have a lot of experience with serialization, and I thought I was being helpful by suggesting you go back to your client to fix their serializer instead of hacking around it's unstructured output. Perhaps there is a valid case for dumping unstructured data that I'm just not seeing. It certainly would be very unconventional, but I'm 100% open to the fact that I may be wrong. Perhaps if you shared the context which disproves my suggestion, I will humbly apologize and accept that I was wrong. Otherwise, let's remain professional and refrain from the personal attacks. 

Exactly, I assumed Alain has the answers and I don't have all the info, and yet you wrote a lenghthy comment about what I suggest or not suggest with the serialization gods etc.. We all agree that its an unusual case, the point is that I think if it was obvious as that Alain would have already ask the client for refactoring. Now after you wrote that you now admit that you might be wrong, you come to my standpoint that only Alain has the answers, and yet you had to first try to claim that theres no chance you dont know. Thats all, not too sensitive, and yet its not friendly to write ad hominem comments like I know your smart enough etc..when I think you're smart enough to understand the subcontext of that remark
 
Alain Verleyen:

I don't think there is an easy "standard" way, so I used an enum and a factory method.

   

...



Now, the vicious circle. I want to extract the original value as an mql basic type :

I added a Get method :

But to call it I need to dynamic_cast the pointer stored.

Problem is 'int' is not known (from a dynamic point of view)

The actual basic type when you have a CParentType pointer like values[i] is unknown, so once again, I would need to use ENUM_TYPE and a switch or try one by one all possible dynamic cast, but I would need to repeat it for each type.

Example, imagine I have to call a functionA with an int parameter, or a functionB with a double parameter.

I will need to declare a variable for any type, then call the "dynamic cast" function, trying one by one :

So the starting generic approach leads to further need to repeat code again and again.

Maybe I am too focused on my project and there is an other solution, but I missed it for now. Any idea ?

yes, heavy messy appears to be in your views on the problem (don't be upset - all OOP-thinkers suffer from this problem - "the type-information should be "encapsulated" somehow by the sence - either explicitly or implicitly")... because such is the language -- strictly-typed

you don't want template_class (for static polymorphism), because you want dynamic polymorphism (but you'd like to avoid type_casting)... - impossible (only if overloading to use)... It seems to me, that you just don't want to accept the reality as far as it is... Of course, you will need to write any generalized_class like std::variant in C++ (BTW you can see its implementation & try to do the same)... - ? perhaps it also uses Type_identification inside ... then it seems for me )) that inspite of your link to wiki - there is really no a person (even among Nobel winners) who have created such a class without type-identification inside - because it is not possible logically (e.g. at least ENUMs should provide this identification - as you know, but do not want to bear it)...

in any case you will need to know somehow the inner m_state of your dynamic object & can use your function as member_method -- in such a case I see no problems (but of course, you need any switch to type when creating the object)... in order to even probably use then e.g. pattern State (if it suits you & you don't like to define the type in the class itself with enum, but need new abstractions)... imho

I strongly believe, that your aim is to avoid great quantity of code-lines & to achive the maximum in generalization... but as I know, the highest level of generalization is provided by templates (or template_classes) - & you will not need the dynamic polymorphism using it... but you will need to create this class (even if it seems to be large)...

and using dynamic polymorphism of course you need type-casting if you really need it (I've heard that it is needed in 5% of cases when polymorphism is used)... but sometimes people prefer something else (to provide exact! type) when the day comes to be in need of RTTI  - & the choice for any substitution depends on the situation... either overloading or using static objects (people prefer just to change the Architecture of the project ) - in order not to use RTTI (where type-casting is really needed)... of course it's worth to avoid RTTI... (in c++ visit-variant was invented for this purpose)

in any case, thank you for the interesting question

here was the attempt to read the File to different type arrays (I didn't see the implementation yet)

OOP issue : idea to break a vicious circle ?
OOP issue : idea to break a vicious circle ?
  • 2019.03.17
  • www.mql5.com
Maybe it was already discussed, but I can't remember or find it...
 
JeeyCi #:

yes, heavy messy appears to be in your views on the problem (don't be upset - all OOP-thinkers suffer from this problem - "the type-information should be "encapsulated" somehow by the sence - either explicitly or implicitly")... because such is the language -- strictly-typed

you don't want template_class (for static polymorphism), because you want dynamic polymorphism (but you'd like to avoid type_casting)... - impossible (only if overloading to use)... It seems to me, that you just don't want to accept the reality as far as it is... Of course, you will need to write any generalized_class like std::variant in C++ (BTW you can see its implementation & try to do the same)... - ? perhaps it also uses Type_identification inside ... then it seems for me )) that inspite of your link to wiki - there is really no a person (even among Nobel winners) who have created such a class without type-identification inside - because it is not possible logically (e.g. at least ENUMs should provide this identification - as you know, but do not want to bear it)...

in any case you will need to know somehow the inner m_state of your dynamic object & can use your function as member_method -- in such a case I see no problems (but of course, you need any switch to type when creating the object)... in order to even probably use then e.g. pattern State (if it suits you & you don't like to define the type in the class itself with enum, but need new abstractions)... imho

I strongly believe, that your aim is to avoid great quantity of code-lines & to achive the maximum in generalization... but as I know, the highest level of generalization is provided by templates (or template_classes) - & you will not need the dynamic polymorphism... but you will need to create this class (even if it seems to be large)...

and using dynamic polymorphism of course you need type-casting if you really need it (I've heard that it is needed in 5% of cases when polymorphism is used)... but sometimes people prefer something else (to provide exact! type) when the day comes to be in need of RTTI  - & the choice for any substitution depends on the situation... either overloading or using static objects (people prefer just to change the Architecture of the project ) - in order not to use RTTI (where type-casting is really needed)... of course it's worth to avoid RTTI... (in c++ visit-variant was invented for this purpose)

in any case, thank you for the interesting question

here was the attempt to read the File to different type arrays (I didn't see the implementation yet)

Thanks for your input. It's somewhat old stuff, I had to make some compromises to get a working and efficient solution. I am not really satisfied about it but I had to deal with the technical limitations (it's not possible to do the same in MQL as C++).
 

You can move the functions into the CType class: 

template<typename T>
class CType : public CParentType
  {
   T                 value;
public:
                     CType(T v) : value(v) {};
                    ~CType(void) {};   
             
  virtual void Function()
   {
   if(typename(value)=="int") FunctionA();      
   else if(typename(value)=="double")FunctionB();
   else if(typename(value)=="string")FunctionC();
   }
   
   void FunctionA()
      {
      Print((string)(int)value+" int processing");
      }
   
   void FunctionB()
      {
      Print((string)(double)value+" double processing");
      }
      
   void FunctionC()
      {
      Print((string)value+" string processing");
      }
  };

then simply call it: 

   CParentType *values[10];
   values[0]=new CType<int>(INT_MIN);
   values[1]=new CType<double>(M_PI);
   values[2]=new CType<string>("str");
 

   values[0].Function();
   values[1].Function();
   values[2].Function();
 
Laszlo Tormasi #:

You can move the functions into the CType class:  

if you see the beginning of the topic - as I understood the author wants to avoid these multiple switches & ifs (that you are suggesting to him in virtual void Function)...

well, therefore I assumed State_pattern can be used for dynamic polymorphism (and it IS used for dynamic polymorphism) -- but really I don't think that it will be shorter...

in any case, your suggestion resembles choosing in "table" (with multiple ifs) - & it is less efficient than overriding the virtual method (like in pattern_State having Context abstraction)... though I really do not know if such pattern suits his goals & really am not thinking that it will be real generalization - just for children of base class State & not for any other types... but if types are common (like int or double) then of course ENUM is ok (as already was mentioned) - if he really needs RTTI... it seems he really do need))

p.s.

BTW I'm now sure, that I do not need dynamic polymorphic objects in my problem - therefore am thankful to this topic

State design pattern in MQL4?
State design pattern in MQL4?
  • 2015.07.05
  • www.mql5.com
Hello, The OO state design pattern takes a context class which has a reference to a state base class, which is subclassed by the state classes that...
 

Probably won't help as well just playing around..
Idea is class that accepts any type (need to add a constructor for each new type possible - basic types for now) without needing to know upfront the type.

And get methods, that are used to retrieve a value, based on a receiving field type - without checking it's type (Overridden get methods for each type do that).

#property strict
class CObject
  {
   ENUM_DATATYPE     m_type;
   int               m_int;
   long              m_long;
   double            m_double;
   string            m_string;
   char              m_char;
   uchar             m_uchar;
   ulong             m_ulong;
   uint              m_uint;
   bool              m_bool;
public:
   void              CObject(const int val);
   void              CObject(const uint val);
   void              CObject(const long val);
   void              CObject(const ulong val);
   void              CObject(const double val);
   void              CObject(const bool val);
   void              CObject(const char val);
   void              CObject(const uchar val);
   bool              GetVal(int &val);
   bool              GetVal(uint &val);
   bool              GetVal(long &val);
   bool              GetVal(ulong &val);
   bool              GetVal(double &val);
   bool              GetVal(bool &val);
   bool              GetVal(char &val);
   bool              GetVal(uchar &val);
  };
CObject::CObject(const int val)
  {
   m_type=TYPE_INT;
   m_int=val;
   Print("New int type");
  }
CObject::CObject(const uint val)
  {
   m_type=TYPE_UINT;
   m_uint=val;
   Print("New uint type");
  }
CObject::CObject(const long val)
  {
   m_type=TYPE_LONG;
   m_long=val;
   Print("New long type");
  }
CObject::CObject(const ulong val)
  {
   m_type=TYPE_ULONG;
   m_ulong=val;
   Print("New ulong type");
  }
CObject::CObject(const double val)
  {
   m_type=TYPE_DOUBLE;
   m_double=val;
   Print("New double type");
  }
CObject::CObject(const bool val)
  {
   m_type=TYPE_BOOL;
   m_bool=val;
   Print("New bool type");
  }
CObject::CObject(const char val)
  {
   m_type=TYPE_CHAR;
   m_char=val;
   Print("New char type");
  }
CObject::CObject(const uchar val)
  {
   m_type=TYPE_UCHAR;
   m_uchar=val;
   Print("New uchar type");
  }
bool CObject::GetVal(int &val)
  {
   val=m_int;
   return(true);
  }
bool CObject::GetVal(uint &val)
  {
   val=m_uint;
   return(true);
  }
bool CObject::GetVal(long &val)
  {
   val=m_long;
   return(true);
  }
bool CObject::GetVal(ulong &val)
  {
   val=m_ulong;
   return(true);
  }
bool CObject::GetVal(char &val)
  {
   val=m_char;
   return(true);
  }
bool CObject::GetVal(uchar &val)
  {
   val=m_uchar;
   return(true);
  }
bool CObject::GetVal(bool &val)
  {
   val=m_bool;
   return(true);
  }
bool CObject::GetVal(double &val)
  {
   val=m_double;
   return(true);
  }

And the use:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   CObject *arr[9];
   int i=1;
   uint ui=2;
   long l=3;
   ulong ul=4;
   double d=5;
   bool b1=true;
   bool b2=false;
   char c=15;
   uchar uc=16;
   arr[0]=new CObject(i);
   arr[1]=new CObject(ui);
   arr[2]=new CObject(l);
   arr[3]=new CObject(ul);
   arr[4]=new CObject(d);
   arr[5]=new CObject(b1);
   arr[6]=new CObject(b2);
   arr[7]=new CObject(c);
   arr[8]=new CObject(uc);
   double d_arr[9];
   int i_arr[9];
   uint ui_arr[9];
   long l_arr[9];
   ulong ul_arr[9];
   char c_arr[9];
   uchar uc_arr[9];
   bool b_arr[9];
   for(int i=0;i<ArraySize(arr);i++)
      {
         arr[i].GetVal(i_arr[i]);
         arr[i].GetVal(ui_arr[i]);
         arr[i].GetVal(l_arr[i]);
         arr[i].GetVal(ul_arr[i]);
         arr[i].GetVal(d_arr[i]);
         arr[i].GetVal(b_arr[i]);
         arr[i].GetVal(c_arr[i]);
         arr[i].GetVal(uc_arr[i]);
      }
    Print("***** int arr *****");
    ArrayPrint(i_arr);
    Print("***** uint arr *****");
    ArrayPrint(ui_arr);
    Print("***** long arr *****");
    ArrayPrint(l_arr);
    Print("***** ulong arr *****");
    ArrayPrint(ul_arr);
    Print("***** double arr *****");
    ArrayPrint(d_arr);
    Print("***** bool arr *****");
    ArrayPrint(b_arr);
    Print("***** char arr *****");
    ArrayPrint(c_arr);
    Print("***** uchar arr *****");
    ArrayPrint(uc_arr);
  }

Result:
Run

 

Just to clarify, the idea of this topic is to be able to write generic code. Which seems not much people are understanding if I read the last few code examples which are not generic at all.

Anyway, it's currently impossible to write truly (complex) generic code in MQL.

Reason: