Interesting code Format using #define

 

I found interesting piece of code, and I don't know if this technique is common in mql5  ...is it beneficial to code like this. Is it common to code  functions in #define, and if Yes  ..then when ??

PS i try to use objects, but if You learn by yourself, the right way is a matter of luck :)  ...so far my motto is if it is working it is good enough :)

#define ForEachSymbol(s,i)  string s=SymbolName(0,true); int os_total=SymbolsTotal(true); for(int i=1;i<os_total;i++,s=SymbolName(i,true))

//| Script  

void OnStart()
  {
   ForEachSymbol(symbol,index)
     {
      //--- prepare data
      double spread=SymbolInfoDouble(symbol,SYMBOL_ASK)-SymbolInfoDouble(symbol,SYMBOL_BID);
      double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
      long digits=SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      string str_spread=DoubleToString(spread/point,0);
      string str_point=DoubleToString(point,(int)digits);
      //--- display data
      Print(index,". ",symbol," spread=",str_spread," points (",
            digits," digits",", point=",str_point,")");
     }
 
Marcin Rutkowski:

I found interesting piece of code, and I don't know if this technique is common in mql5  ...is it beneficial to code like this. Is it common to code  functions in #define, and if Yes  ..then when ??

PS i try to use objects, but if You learn by yourself, the right way is a matter of luck :)  ...so far my motto is if it is working it is good enough :)

It looks like a function but it's a macro, very different. Personally I don't like this way to code. It's cryptic, in your code example you see all at once, so it's not a problem, but usually you will have this define far away. What is this symbol and index variable ? where are they declared and set.

And it's impossible to debug...which is not a big deal for a small snippet like that, but when you start with macro what is the limit ? Well of course there are benefits to use it, it's shorter to write. But there are others, better ways to create reusable code. So, it's a matter of taste, do as you want and deal with the pros and cons. If your code is only for you, that would probably not be a problem. If you code in team or publicly, you should never use such things in my opinion.

By the way, there is a bug in your macro

 
Marcin Rutkowski:

I found interesting piece of code, and I don't know if this technique is common in mql5  ...is it beneficial to code like this.

I believe the particular macro you posted is called syntactic sugar. Arguably it "is designed to make things easier to read or to express." Also, "it can be removed from the language without any effect on what the language can do."

I agree with what @Alain Verleyen posted. I avoid this sort of construct as a general rule.

When I use a macro:

1. if it substantially increases the readability of my code.

2. if it is small and atomistic (self-contained)

So, one I do use is:

#define assert(condition, message, returnVal)                                                      \
    if(!(condition)) {                                                                             \
        ALERT(StringFormat("Assertion [%s] failed! %s", #condition, message ));                    \
        return returnVal;                                                                          \
    }

It's nice because it will print out the actual condition that failed (#condition).

Sometimes encapsulate "atomistic" code into a macro. In this case, it's pretty obvious what the macro does from the name, so another programmer wouldn't have too big a problem with it. It just makes the code a little cleaner.

#define DELETE(ptr) { if ( ptr != NULL ) delete ptr; ptr = NULL; }

This is one of my favorites because it's crisp and clean. I think I lifted this from @whroeder1 some time ago. Arguably, it would be better written as a regular function.

#define EMA(P, C, L) ((P) + (2.0/((L)+1.0))*((C)-(P)))

So, I am not a purist who doesn't use any macros, but I wouldn't use the macro you posted because it goes a little too far in restructuring how for() loops work, and I don't personally see the increased readability over a regular for() loop.

 
Anthony Garot:
...

Nice complement to my answer to show positive usage of macros. Good work.

Just an issue :

#define DELETE(ptr) { if ( ptr != NULL ) delete ptr; ptr = NULL; }

This is not correct as a pointer can also be an automatic pointer.

   C obj1;
   C *ptr1=&obj1;       // Same as GetPointer(obj1);
   DELETE(ptr1);

In this case your code will result in a warning in the log.

delete non dynamic object

Should be :

#define DELETE(ptr) { if ( CheckPointer(ptr)==POINTER_DYNAMIC ) delete ptr; ptr = NULL; }
 
Alain Verleyen:

Should be :

Excellent! Thank you.

 

I like this...

bool safe_delete(void *ptr)
{
   if(CheckPointer(ptr) == POINTER_DYNAMIC) {
      delete ptr;
      ptr = NULL;
      return true;
   }
   return false;
}
 
nicholi shen:

I like this...

Yes but it's a topic about macros :-D
 
Alain Verleyen:
Yes but it's a topic about macros :-D

I personally like well developed for_each macros. I think anyone with any amount of programming experience would know exactly what these do without having to see its implementation. 

#define forEach(TYPE, VAR, ARRAY) \
   TYPE VAR=NULL; \
   for(int i##VAR=0; i##VAR<ArraySize(ARRAY)&&((VAR=ARRAY[i##VAR])!=NULL||true); i##VAR++)

void OnStart()
{
   string arr[] = {"USD", "EUR", "GBP"};
   forEach(string, c1 , arr){
      forEach(string, c2, arr){
         if(c1 != c2) {
            Print(c1, c2);
         }
      }
   }   
}
...which in my opinion is much more idiomatic than 
void OnStart()
{
   string arr[] = {"USD", "EUR", "GBP"};
   string c1 = NULL; 
   for(int i=0; i<ArraySize(arr); i++) {
      c1 = arr[i];
      string c2 = NULL;
      for(int j=0; i<ArraySize(arr); j++) {
         c2 = arr[j];
         if(c1 != c2) {
            Print(c1, c2);
         }
      }
   }   
}
 

can be useful for Call Source

#define LN __LINE__
#define DLN "line " + string(__LINE__)
#define FL_LN __FILE__ + ":" + string(__LINE__)
#define FN_LN __FUNCTION__ + "():" + string(__LINE__)
#define FN_F __FUNCTION__ + "() " + __FILE__
#define FN_F_LN __FUNCTION__ + "() " + __FILE__ + ":" + string(__LINE__)
Reason: