Best method to programmatically determine the type ID?

 

I have a need to determine type of a variable which can then be used is a switch statement, and my thoughts are to hash the "typename" string of said var. Do you know a better way?

void OnStart()
{
   int               a; Print(type_id(a));
   uint              b; Print(type_id(b));
   double            c; Print(type_id(c));
   CObject           o; Print(type_id(o));
   ENUM_TIMEFRAMES   t; Print(type_id(t));
}

template <typename T>
int type_id(const T &var)
{
   string tname = typename(var);
   int len = StringLen(tname);
   int hash = 0;
   if(len > 0)
      for(int i=0; i<len; i++)
         hash = (31 * hash) + tname[i];
   return hash;
}

Secondary question, since when are MQL strings subscriptable (can be accessed like arrays)???

   string s = "abcdefg";
   for(int i=0; i<StringLen(s); i++)
      Print(CharToStr(s[i]));
 
nicholi shen:

Secondary question, since when are MQL strings subscriptable (can be accessed like arrays)???

Forum on trading, automated trading systems and testing trading strategies

New MetaTrader 4 build 1010: New opportunities of MQL4

forex-tsd, 2016.08.20 14:31

MetaTrader 4 platform update is to be released on Thursday, August 18, 2016. The new version features the following changes:

  1. MQL4: Added support for the operator [ ] for strings. The operator enables users to get a symbol from a string by index. If the specified index is outside the string, the result is 0.
  2. string text="Hello";
    ushort symb=text[0];  // Will return the code of symbol 'H'
 
nicholi shen:

I have a need to determine type of a variable which can then be used is a switch statement, and my thoughts are to hash the "typename" string of said var. Do you know a better way?

When I have needed such things, I just use if/else/else/. . . .

Your idea has merit.

It might get tricky with types you define yourself, though. Consider EnIndicatorType (below) which is an enum. Enums act as integers, so in my code, it's perfectly acceptable to store that in a long value; but your type_id() code might give confusing results (or confusing code).

string type = typename(value);
if (type == "string")
{
    n.stringValue = (string) value;
}
else if (type == "long" || type == "int" || type == "EnIndicatorType")
{
    n.longValue = (long) value;
}
else
{
    Print(StringFormat("Unknown type [%s]", type));
}

But for "standard" types, your type_id() should work.

It might be interesting to somehow add-in the Print() format type with each type.

E.g.

%d for integers, longs, etc.

%f for doubles, floats, etc.

Just thinking aloud, of course.

 
Anthony Garot:

When I have needed such things, I just use if/else/else/. . . .

Your idea has merit.

It might get tricky with types you define yourself, though. Consider EnIndicatorType (below) which is an enum. Enums act as integers, so in my code, it's perfectly acceptable to store that in a long value; but your type_id() code might give confusing results (or confusing code).

But for "standard" types, your type_id() should work.

It might be interesting to somehow add-in the Print() format type with each type.

E.g.

%d for integers, longs, etc.

%f for doubles, floats, etc.

Just thinking aloud, of course.

I'm not sure I follow what you mean by it getting tricky for types you define yourself....

I think you are right though... and the cost of hashing the typename offsets any potential switch statement optimization.  

Here's something simple that works for any type in any condition. (concept stolen from Python ;)

class _type { 
public: 
   static string typename_modify(string tn) {
      int ptr_char_pos = StringFind(tn, "*");
      if(ptr_char_pos > 0)
         tn = StringSubstr(tn, 0, StringLen(tn) - 1);
      return tn;
   }
};

#define isinstance(VAR, VARTYPE) \
   (_type::typename_modify(typename(VAR)) == _type::typename_modify(typename(VARTYPE)))


Usage:

#include <Object.mqh>

class Foo : public CObject {};

void OnStart()
{
   Foo *foo_dynamic = new Foo();
   Foo foo_static;
   
   if(isinstance(foo_dynamic, Foo))
      Print("Pointers work");
      
   if(isinstance(foo_static, Foo))
      Print("Static obj refs work"); 
      
   if(!isinstance(1.23456, int))
      Print("implicitly cast double is not type int!");
      
   string str = "It works for any type in any circumstance";
   if(isinstance(str, string))
      Print("Yup, string works as well.");
      
   delete foo_dynamic;
}
 
nicholi shen:

Here's something simple that works for any type in any condition. (concept stolen from Python ;)

Nice and clean.

Reason: