Friday, September 29, 2017

Very simple "for-each" patterned programming trick

Quite a few times during coding there issome need for repetitive tasks. Something like, in C++:

...
ourDoubleMatrix A, B, C, u1, u2; 
double* A_ptr = A.Data(); A.Resize_Matrix(a,b); Eigen::Map<eigenmat> A_mat(A_ptr, A.Rows(), A.Columns()) ;
double* B_ptr = B.Data(); B.Resize_Matrix(a,b); Eigen::Map<eigenmat> B_mat(B_ptr, B.Rows(), B.Columns()) ;
... // you guessed it.

or, in VBA:
Function do_some_stuff(data As Variant, data1 As Variant, data2 As Variant, moredata As Variant, evenmoredata As Variant, somemoredata As Variant, andcantherebemoredata As Variant) As Variant
 ...
 Dim v_data As Variant: v_data = Application.Transpose(Application.Index(data, 0, 1)): count = data.Rows.Count: ReDim Preserve v_data(1 To (count + addcount))
 Dim v_data1 As Variant: v_data1 = Application.Transpose(Application.Index(data1, 0, 1)): count = data1.Rows.Count: ReDim Preserve v_data1(1 To (count + addcount))
 ... ' and again you guessed it


Doing this via copy-and-paste with substitution of variable names is, well, time-consuming and tedious. Much more importantly, it is very error-prone (think of what would happen if you end up writing double* u2_ptr = u1.Data() or
v_data2 = Application.Transpose(Application.Index(data1, 0, 1)) - such mistakes are very easy to make but would take hours of thankless debugging to spot).

The solution would be to have a tool that would do "for each item in this list of variables, code so-and-so".

Here's a very simple trick to do it in a few seconds, literally:

  1. Code up your first line. (Make sure it is correct.) 
  2. Set up an Excel (or any other free equivalent) spreadsheet:
    • copy your list of variables into column A
    • copy your ready line of code into cell B1
    • put this formula into cell B2: =SUBSTITUTE(B$1,A$1,A2)
  3. Then simply replicate the formula in B1 to the number of elements in the column A (the quickest way is to select B1 then double click the lower right corner of that sell), and recalculate the sheet if needed.
  4. Copy-paste the resulting column B to your code.
That's it!




Of course there are subtleties, namely that you need to make sure that the substitution is done correctly -- namely that the variable name in the first line is unique enough not to match anything else in the code (choosing a is probably a bad idea :).

And of course you can easily extend this to include multiple substitutions, increments, case-dependent logic, all the way to some quite sophisticated meta-programming. Your mileage may vary - just make sure that coding the spreadsheet doesn't take significantly more time than copy-pasting it "the plain old way".

I can almost hear someone screaming that this is very poor programming style, and, well, I largely agree. Yes, a much better solution is to avoid scenarios when you need to code repetitive stuff altogether, for example by encapsulating all set-up stuff in their respective classes. And shortcuts such as this one should never promote (or be used as an excuse for) lousy coding.

However, we do not always have ownership of the code and its design, nor do we always have the liberty of going for "let's drop all other tasks and rework that code". In other words, there are occasions when you're in Rome and have to do as Romans do. So if/when the need really arises, it's better to have a quick and easy way to write repetitive code, as opposed to having a tedious and bug-spawning way.

In other words: if you have to write lousy code, better write a reliable lousy code.

After all, isn't this exactly what template programming is all about?