MQL equivalent to Python's None type? - page 5

 
nicholi shen:

I am right. 


There is a need for the standardization of the representation of absent of values (henceforth referred to as "None"). Currently, the way to set a variable to None is to set it at the edge of its limit. (eg. double x = DBL_MAX) These vary greatly from type to type. Additionally there is currently no way to set None values using templates. This library solves these issues. If you want to continue using a plethera of MQL constants and making overloaded funcitons instead of using template then don't use it. Those who understand the concept of None will instantly see the value in having both 1. new constants defined with prefix NONE_XXX and 2. A macro which you can pass the type and receive the None value in return. Either can be used or None (pun intended), it's your choice. 

I agree with you about the need, I just think there is more then one way to solve the problem, there is not a must for using a static class and it doesn't mean you have to have plethora of MQL constants and overloaded functions, for example if you use CObject. 
 
Amir Yacoby:
I agree with you about the need, I just think there is more then one way to solve the problem, there is not a must for using a static class and it doesn't mean you have to have plethora of MQL constants and overloaded functions, for example if you use CObject. 

Ok... then please allow me to present a challenge for you. Show me how I can do this... 


// This code will not change, only your implementation of None.mqh!
#include <None.mqh>
template <typename T>
int array_resize_with_none_init(T &array[], int new_size)
{
   int total = ArrayResize(array, new_size);
   for(int i=0;i<total;i++)
      array[i] = NONE(T);
   return total;
}

...without cluttering the global namespace with unnecessary functions.


Just to make sure we're on the same page... I'm using the naming convention for marking something private (i.e. _NoneType) for a class with only static methods as a way to create a private namespace, which I'm doing intentionally to keep the functions out of the global namespace. The only things globally exposed are the NONE_TYPE constants and the NONE macro.  

Edit: and while we're on the topic of namespace, MQL allows inline scoping. Within this scope you can define functions inside of functions provided you use the class/static method pattern. I'm pretty sure this has to be new because I don't remember class definitions obeying scope in the past. 

void OnStart()
{  
   string words[] = {"THIS","IS","JUST","A","STUPID","EXAMPLE"}; 
   {// inline namespace
      //defining function within an inline namespace inside of a function
      class Str{public:template<typename T>
      static string join(string joiner,T &array[]){
         string res = NULL;
         int total = ArraySize(array);
         for(int i=0; i<total; i++){
            res += string(array[i]);
            if(i < total -1)
               res += joiner;
         }
         return res;
      }};
      Print(Str::join(" ", words)); //THIS IS JUST A STUPID EXAMPLE
   }
   Print(Str::join(" ", words)); //Compilation error: 'Str' - import not defined
}
 
nicholi shen:

Ok... then please allow me to present a challenge for you. Show me how I can do this... 

...without cluttering the global namespace with unnecessary functions.



Once again I have to tell you that I write the code for classes only. Did you place a global function on purpose or you just not listen to what I say? If you make it a method of a class I can post a code.

nicholi shen:

Just to make sure we're on the same page... I'm using the naming convention for marking something private (i.e. _NoneType) for a class with only static methods as a way to create a private namespace, which I'm doing intentionally to keep the functions out of the global namespace. The only things globally exposed are the NONE_TYPE constants and the NONE macro.  

Again I'm hearing arrogance, you seem to not believe that I understand what you mean.. why is that?

 
Amir Yacoby:

Once again I have to tell you that I write the code for classes only. Did you place a global function on purpose or you just not listen to what I say? If you make it a method of a class I can post a code.

Again I'm hearing arrogance, you seem to not believe that I understand what you mean.. why is that?

I'm sorry if that's they way it's coming across, but I feel the need to be specific because you don't seem to understand that I'm using a class as a pseudo namespace and that None has to be global and not a class member.

Would you also argue that the global DBL_MAX constant should be a member of CObject and only available to its descendants?
 
nicholi shen:
Because you don't seem to understand that I'm using a class as a pseudo namespace and that None has to be global and not a class member.

Would you also argue that the global DBL_MAX constant should be a member of CObject and only available to its descendants?
No, it's not because I don't "seem" to understand. It seems like you can not comprehend that I can understand and disagree.
class CObject
  {
private:
   double   None(const double _)  const   { return DBL_MAX;   }
   int      None(const int _)     const   { return INT_MAX;   }
   uint     None(const uint _)    const   { return UINT_MAX;  }
   long     None(const long _)    const   { return LONG_MAX;  }
   ulong    None(const ulong _)   const   { return ULONG_MAX; }
   char     None(const char _)    const   { return CHAR_MAX;  }
   uchar    None(const uchar _)   const   { return UCHAR_MAX; }
   short    None(const short _)   const   { return SHORT_MAX; }
   ushort   None(const ushort _)  const   { return USHORT_MAX;}
   string   None(const string _)  const   { return "__NULL-*-*-STRING__";}
   color    None(const color _)   const   { return clrNONE;   }
   datetime None(const datetime _) const  { return -1;        }
   template<typename T>
   T        None(const T _) const { return NULL;     }
protected:
   template<typename T>
   T None() const { return None((T)NULL);}
  };

The only method available is None<>() - just one method, protected.
And the templated ArrayRing (you can find the Init() inside, as you wanted)

template<typename T>
class CArrayRing : public CObject
  {
private:
   T                 m_data[];         // ring buffer of data
   int               m_size;           // buffer size
   int               m_last_pos;       // last buffer element position
   T                 m_filling;        // value, which used for the array filling
public:
                     CArrayRing();
                    ~CArrayRing() { ArrayFree(m_data);                         }
   //--- buffer initialization method:
   bool              Init(int size,T volue=NULL);
   //--- method returns the buffer size:
   int               Size() { return m_size-1;                           }
   //--- method changes the ring buffer size:
   bool              Resize(const int size);
   //--- method of adding a new element to the buffer:
   void              Add(T element);
   //--- method returns the value of element with the specified index:
   T                 At(const int index) const;
   T operator[](const int index) const     { return(At(index));                         }
   //--- method returns the value of the last element stored in the buffer:
   T                 Last() const                  { return(m_data[m_last_pos]);                }
   //--- method overwrites the value of the last element in the buffer:
   void              Last(T element) { m_data[m_last_pos]=element;                }
   //--- method overwrites the value of element with the specified index:
   bool              Update(T element,const int index=0);
  };
//+------------------------------------------------------------------+
//| Constructor.                                                     |
//+------------------------------------------------------------------+
template<typename T>
CArrayRing::CArrayRing()
  {
   m_last_pos=0;                          // last element position
   m_filling=None<T>();                 // value for buffer filling
   m_size=ArraySize(m_data);              // get size of the ring buffer
  }
//+------------------------------------------------------------------+
//| Buffer initialization method.                                    |
//+------------------------------------------------------------------+
template<typename T>
bool CArrayRing::Init(int size,T volue=NULL)
  {
   m_last_pos=0;                          // last element position
   volue=volue==NULL ? None<T>() : volue;
   m_filling=volue;                       // value for buffer filling
   m_size=ArraySize(m_data);              // get size of the buffer   
   bool result=Resize(size);              // create a buffer with the desired size
   for(int i=0;i<ArraySize(m_data);i++)
      m_data[i]=m_filling;
   return(result);
  }
//+------------------------------------------------------------------+
//| Set the new size of the array.                                   |
//+------------------------------------------------------------------+
template<typename T>
bool CArrayRing::Resize(const int new_size)
  {
//--- check
   if(new_size<0) return(false);
//--- increase array size:
   if(new_size>m_size)
     {
      int set_size=ArrayResize(m_data,new_size);
      if(set_size<0) return(false);
      //--- copy elements to restore their order:
      if(set_size>m_size)
        {
         for(int i=m_size-1,j=set_size-1;i>m_last_pos;i--,j--)
           {
            m_data[j]=m_data[i];
            m_data[i]=m_filling;
           }
        }
      m_size=set_size;
      //--- result:
      return(true);
     }
//--- reduce array size:
//--- prepare array to reduce the size:
   if(new_size>m_last_pos+1)
      for(int i=m_size-1,j=new_size-1;j>m_last_pos;i--,j--) m_data[j]=m_data[i];
   else
     {
      for(int i=m_last_pos+1-new_size,j=0;i<=m_last_pos;i++,j++) m_data[j]=m_data[i];
      m_last_pos=new_size-1;
     }
//--- reduce the size:
   m_size=new_size;
   ArrayResize(m_data,new_size);
//--- result:
   return(true);
  }
//+------------------------------------------------------------------+
//| Adding a new element to the buffer.                              |
//+------------------------------------------------------------------+
template<typename T>
void CArrayRing::Add(T element)
  {
   m_last_pos=++m_last_pos%m_size;
   m_data[m_last_pos]=element;
  }
//+------------------------------------------------------------------+
//| Gets the element at the specified index.                         |
//+------------------------------------------------------------------+
template<typename T>
T CArrayRing::At(const int index) const
  {
//--- check the index correctness:
   if((index/m_size)==0)
      //--- return the value of element with the specified index:
      return(m_data[(m_size+m_last_pos-index)%m_size]);
//--- if the index is wrong:
   return(None<T>());
  }
//+------------------------------------------------------------------+
//| Update the element at the specified position in the array.       |
//+------------------------------------------------------------------+
template<typename T>
bool CArrayRing::Update(T element,const int index=0)
  {
//--- check the index correctness:
   if((index/m_size)==0)
     {
      //--- update
      m_data[(m_size+m_last_pos-index)%m_size]=element;
      //--- successful
      return(true);
     }
//--- if the index is wrong:
   return(false);
  }

test

class CTest : public CObject
  {
private:
   int               m_id;
public:
                     CTest(int id) {m_id=id;}
   int Get() {return m_id;}
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   CArrayRing<double>ringd;
   ringd.Init(50);
   for(int i=0;i<50;i++)
      ringd.Add((double)i);
   for(int i=49;i>=0;i--)
      Print("ring ",i," is ",ringd.At(i));
   printf("last is %d",ringd.Last());

   CArrayRing<short>rings;
   rings.Init(50);
   for(short i=0;i<50;i++)
      rings.Add((short)(i*2));
   for(int i=49;i>=0;i--)
      Print("ring ",i," is ",rings.At(i));
   printf("last is %d",rings.Last());

   CArrayRing<datetime>ringdt;
   ringdt.Init(50);
   for(int i=49;i>=0;i--)
      Print("ring date  ",i," is initialized to ",ringdt.At(i));
   for(short i=0;i<50;i++)
      ringdt.Add(iTime(Symbol(),PERIOD_D1,i));
   for(int i=49;i>=0;i--)
      Print("ring ",i," is ",ringdt.At(i));
   printf("last is %d",ringdt.Last());

   CArrayRing<CTest*>ringtst;
   ringtst.Init(50);
   for(short i=0;i<50;i++)
      ringtst.Add(new CTest(i));
   for(int i=49;i>=0;i--)
      Print("ring ",i," is ",ringtst[I].Get());
   printf("last is %d",ringtst.Last());
  }
 
Amir Yacoby:
No, it's not because I don't "seem" to understand. It seems like you can not comprehend that I can understand and disagree.
The only method available is None<>() - just one method, protected.
And the templated ArrayRing (you can find the Init() inside, as you wanted)
test

Your code, however you decide to implement it, should be able to compile and pass these unit tests. 

//+------------------------------------------------------------------+
//|                                                   NoneScript.mq5 |
//|                                                      nicholishen |
//|                                                    interwebs.com |
//+------------------------------------------------------------------+
#property copyright "nicholishen"
#property link      "interwebs.com"
#property version   "1.00"
#include <None.mqh>

//--- Global variables
double g_double = NONE_DOUBLE;
string g_string = NONE_STRING; 
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
   int array[];
   int total = array_resize_init_none(array, 10);
   printf("%s: %s", 
      assert_equals(INT_MAX, array), 
      "Array test."
   );
   printf("%s: %s", 
      assert_equals(INT_MAX, NONE_INT), 
      "NONE_INT constant test."
   );
   printf("%s: %s", 
      assert_equals(INT_MAX, NONE(int)), 
      "NONE(int) MACRO test."
   );
   printf("%s: %s", 
      assert_equals(g_double, DBL_MAX), 
      "Global var, type double test."
   );
   printf("%s: %s", 
      assert_equals(DBL_MAX, NONE_DOUBLE, NONE(double)), 
      "All type double values correct"
   );
   
}
//+------------------------------------------------------------------+

template <typename T>
int array_resize_init_none(T &array[], int size)
{
   int total = ArrayResize(array, size);
   for(int i=0; i<total; i++){
      array[i] = NONE(T);
   }
   return total;
}

template <typename T>
string assert_equals(T value1, T value2)
{
   if(value1 != value2)
      return "Failed";
   return "Passed";
}

template <typename T>
string assert_equals(T value1, T value2, T value3)
{
   if(!(value1 == value2 && value2 == value3))
      return "Failed";
   return "Passed";
}

template <typename T>
string assert_equals(T value1, T &array[])
{
   for(int i=ArraySize(array)-1; i>=0; --i)
      if(value1 != array[i])
         return "Failed";
   return "Passed";
}
 
nicholi shen:

I am right. 


There is a need for the standardization of the representation of absent of values (henceforth referred to as "None"). Currently, the way to set a variable to None is to set it at the edge of its limit. (eg. double x = DBL_MAX) These vary greatly from type to type. Additionally there is currently no way to set None values using templates. This library solves these issues. If you want to continue using a plethera of MQL constants and making overloaded funcitons instead of using template then don't use it. Those who understand the concept of None will instantly see the value in having both; 1. new constants defined with prefix NONE_TYPE and 2. A macro which you can pass the type and receive the appropriate None value in return. Either can be used or None (pun intended), it's your choice. 

I showed you that I can template, and standardize without using the static class (it does not matter to me you restrict the access with a macro).
 
nicholi shen:

Your code, however you decide to implement it, should be able to compile and pass these unit tests. 

Again, you code for functions, and for me it does not worth introducing static classes for that(it does not matter to me that you restrict the access with the macro). It's my choice, ok? Live with that, and don't come up again and again with same thing. I need that from class scope because I keep oo. that's it, simple.
 
Amir Yacoby:
I showed you that I can template, and standardize without using the static class (it does not matter to me you restrict the access with a macro).

Then you are redefining the purpose of 'None' for your own edge case and need to open your own thread because we are not discussing the same concept. 

 
nicholi shen:

Then you are redefining the purpose of 'None' for your own edge case and need to open your own thread because we are not discussing the same concept. 

We talked about it already and I said it clearly. You also acknoledged it. Then you come back to it, among other wrong ideas that it should be public or I must clutter etc. Well no, it shouldnt be public and for me its the better solution. Anyway, our stands are clear as I said, let the people choose. Thats it, its your thread but I think there are many people that will agree with me also so I wrote here. Have a good day.
Reason: