Debugging DSL


As a functional language, DSL does not use pointers, does not allow any explicit allocation of memory, and has no control of flow. Henceforth nothing much can go wrong. Programming DSL is very much like programming spreadsheet formulas. The primary difference is that a spreadsheet displays values in a visible way. Much of DSL code however just runs in the background, possibly nested deep in function code. What if you wanted to inspect the current value in a series while the strategy is running, or assert that his has a certain value? Well, there are a number of debugging aids for DSL:

 

DPRINT()

This macro prints the name of the variable or expression and its value to standard output.

ASSERT()

This macro is only enabled in debug mode and asserts that an expression is true. IF the expression is false an exception is thrown with line and file information as well as the strategy bar timestamp.

VERIFY()

The equivalent of ASSERT() but enabled also during release mode.

 

Floating Point Rounding Errors


For unit-testing purposes, we often need to check for equality between two floating point values that should be identical, but are no because of floating point rounding errors. This often happens when testing the equivalence of an optimized algorithm versus its non-optimized counterpart. In such cases you can use ASSERT() in conjunction with the FP_EQUAL(sref<double> a, sref<double> b, double precision = 1e-12) function which checks that two floating point numbers are identical up to a certain tolerance. This tolerance is not a fixed number of decimal points but rather depends on the size of the larger of the first two arguments.

 

A Demonstration - Tutorial 206


Tutorial 206 reuses the lambda functions that were defined for tutorial 203. In this case, we simply compare the output of the DSL functions implemented via lambdas with the output of the library's own DSL functions.

 

                    void on_prepare_dsl(void)   override

                    {

                              auto rand = RAND(-5.0, 5.0);              // Generate a random variable

                              auto abs = ABS_FROM_LAMBDA(rand);         // Absolute value of random variable

                              DPRINT(rand);                             // Print random variable to standard output

                              DPRINT(abs);                              // Print absolute value to standard output

 

                              ASSERT(abs == ABS(rand));                 // checking against built in function

 

                              auto avg = AVERAGE_FROM_LAMBDA(rand, 10);

                              ASSERT(FP_EQUAL(avg, AVERAGE(rand, 10))); // checking against library function

                                                                        // with some tolerance for floating point

                                                                        // rounding errors. Tolerance can be set as

                                                                        // argument to FP_EQUAL

                              VERIFY(CONST(1) + CONST(1) == CONST(2));

                              DPRINT(CONST(1) + CONST(1) == CONST(2));

                    }

The on_prepare_dsl() member is the only code of interest here. We already covered the lambda functions in the previous section. The output of this code is as follows:

 

=========================================

Tutorial:    204

=================================

'rand': -2.96560253900606252

'abs': 2.96560253900606252

'CONST(1) + CONST(1) == CONST(2)': true

'rand': -3.51353829924798067

'abs': 3.51353829924798067

'CONST(1) + CONST(1) == CONST(2)': true

'rand': 4.54656397913269927

'abs': 4.54656397913269927

'CONST(1) + CONST(1) == CONST(2)': true

'rand': 3.56687167160372987

'abs': 3.56687167160372987

'CONST(1) + CONST(1) == CONST(2)': true

'rand': 1.05604712293856906

'abs': 1.05604712293856906

'CONST(1) + CONST(1) == CONST(2)': true

'rand': -2.81035807864050335

'abs': 2.81035807864050335

'CONST(1) + CONST(1) == CONST(2)': true

'rand': 3.74160828505214482

'abs': 3.74160828505214482

'CONST(1) + CONST(1) == CONST(2)': true

'rand': 1.19618170107625854

'abs': 1.19618170107625854

'CONST(1) + CONST(1) == CONST(2)': true

'rand': -4.44008395994084015

'abs': 4.44008395994084015