Thursday, 27 September 2012

GetWindowText() and IsEmpty() doesn't work on Windows 7 ?!?!


Normally, when someone comes to you and blames some bugs on compiler, or even worse, on the computer, you'd only smile mildly and give him some of the age-old programming wisdom. I said normally. Because today I tried to debug some Windows code ported from VisualStudio 2005 to VisualStudio 2010, and stumbled upon two impossible-to-think-of bugs.  And as googling didn't bring ther right results immediatelly, I will document it here for myself an others. Let's pray Google indexes it* for the sake of all the poor programmers forced to work on Windows!

As a matter of fact, I've seen a similiar problem when initially porting the code, but it was only one reptitive  bug, so I forgot about it. Here a code snippet as illustration:

  // bug VisStudio 2010: "LPCSTR comparison not working in 64 bit OS"
  // - workaround: use CString
  //int iSelSysPath = LBCBFindStringExact(*this, IDC_CB_SYSTEMPATH, 0, TRUE, m_ActSubrange.cSystemPath);
  CString sysPath(m_ActSubrange.cSystemPath);
  int iSelSysPath = LBCBFindStringExact(*this, IDC_CB_SYSTEMPATH, 0, TRUE, sysPath);
Ok, that may happen, I'm not particuralry picky on such errors. But today, there were two more bugs I didn't catch initially. One ratehr simple, so I only cite it here for reference reasons:

  // bug Windows 7!!!
  //m_cbSysPath.GetWindowText(m_pBMMSett->Station[m_iStation].Subrange.cSystemPath, 
  // ARRAY_SIZE (m_pBMMSett->Station[m_iStation].Subrange.cSystemPath));
  //m_strPath = m_pBMMSett->Station[m_iStation].Subrange.cSystemPath; 
  CString tmp;
  ::LB_CB_GetLBText(m_cbSysPath.m_hWnd, LB_CB_GetCurSel(m_cbSysPath.m_hWnd, true), tmp.GetBuffer(), true);
  m_strPath = tmp;
As you can see, you cannot read the contents of a combo box! Its filled, but you continue to get an empty striong over and over again! Fortunately, like the bug above, this is a known issue, and my collague told me that that GetWindowsText() fails when the addres of the target isn't even-valued. Well, somehow creepy, but if that's a known issue, then what the fuss...

The next bug however wasn't that simple to fix. In fact we stared some 15 minutes at a piece of code where the IsEmpty() method of the MFC's (notorious) CString class reported true for an obviously non empty string! How can things get that wrong? The reason was found after some googling (though some deeper and harder debgging would solve it too), here's the relevant post:
I wonder if your getting a referencing problem.  CString attempts to not create new values if it thinks it can use the same one for multiple occurrences.  I've been caught by this before.  I usually force the issue by using the LPCTSTR operator like:

CString cs = (LPCTSTR) csValue;
Might be worth a try anyway.
Tom  
And he (i.e. Tom) was right, because the following change forced a copy and in result fixed the problem:
 
  //bool empty = m_aStrSettPath.IsEmpty(); <-- not working! internal CString cache issues
  CString p = (LPCTSTR)m_aStrSettPath[i];  
  bool empty = p.IsEmpty()  
But now hold on! The basic operation on strings is broken? Can it get any worse? If you can -stay away from MFC, if you cannot - wel,l I hope you'll be abble to google this post.

---
* an that's the reason for the grammatical error in the title of this post

Friday, 7 September 2012

Coding Styles Again, or Getting LISPy?


Although in my previous post I argued that coding styles and formatting are only smoke and mirrors, latetly I found myself increasingly entangled in a dilemma concerning just that question. Namely, I suddenly found pleasure in writing my C++ statements using expressions rather than direct flow control constructs.
Want an expample? Here it is:
  // housekeeping
  (type == QAmmMeasModel::MeasChannelNode) 
    ? removeItemRef(m_measDefEntries, m_measDefFilesSz, defFileName, defFileIndex)
    : removeItemRef(m_rangeDefEntries, m_rangeDefFilesSz, defFileName, defFileIndex);
instead of the more mundane (or, if you want, normal):
  if(type == QAmmMeasModel::MeasChannelNode) 
  {
    //........
  }
  else
  {
    //........
  }
As such, it is rather to be seen as an innocent idiosyncracy of mine, but it didn't stopped there, culminating in the following substituton. Instead of the rather boring:
 // houskeeping
 if(type == QAmmMeasModel::MeasChannelNode) 
 {
   assert(m_measDefEntries.contains(key));
   assert(m_measDefFiles.contains(defFileName));

   m_measDefEntries.remove(key);
   
   if(m_measDefFiles[defFileName] == 1)
     m_measDefFiles.remove(defFileName);
   else 
     m_measDefFiles[defFileName]--;
 }
 else
 {
   assert(m_rangeDefEntries.contains(key));
   assert(m_rangeDefFiles.contains(defFileName));

   m_rangeDefEntries.remove(key);
  
   if(m_rangeDefFiles[defFileName] == 1)
     m_rangeDefFiles.remove(defFileName);
   else 
    m_rangeDefFiles[defFileName]--;
 }
I came to consider using something more funky, like:
 // lispy?
 (type == QAmmMeasModel::MeasChannelNode) ?
  (m_measDefEntries.remove(key),   
     ((m_measDefFiles[defFileName] == 1) ? 
      m_measDefFiles.remove(defFileName) : m_measDefFiles[defFileName]--)) :
  (m_rangeDefEntries.remove(key),   
     ((m_rangeDefFiles[defFileName] == 1) ? 
      m_rangeDefFiles.remove(defFileName) : m_rangeDefFiles[defFileName]--));
You must admit that the second version is more succint, looks better and transmits some indefinite "guru" feeling. Unfortunately I had to let the asserts go, but it didn't occur to me as a great loss. So why did I delete the second version in the end? Simple. It was written for my client, and should be readable to all C++ programmers. In that way coolness was sacrificed on the altar of mediocrity ;) for the filthy lucre's sake ;).

Later in the day I chose the simpler solution and just wrote the removeItemRef() function hiding the ugly if() clause, but if I didn't do it, what do you think, which of the two versions should I had included in the code?

Monday, 3 September 2012

Static vs Dynamic - the LISP experiences


Maybe you happen to remember my recent post about static and dynamic languages with the main assertion that the type information is maybe superfluous but helpful for documentation and refactoring. You might be tempted to retort: docs & refactoring are for sissies, you wimp! But wait a moment, who are the most notorious hackers out there? You are right, the LISP hackers. From them you'd expect the most ruthless hacks and also despising of the programming aids mere mortals are using. At least as far as the programming folklore is concerned.

But if you a little bit look closer... Heres the answer* given to a simple question "What you dislike the most about Lisp?":
I must say that the lack of static typing really gets in the way on larger projects. Being able to confidently change datatypes and function signatures, knowing that the compiler will point out most inconsistencies that you introduce, is something that I've really come to appreciate after working with Rust and Haskell. Test coverage helps, of course, but I'm not a very diligent test writer, and tend to feel that type signatures are easier to maintain than an exhaustive test suite.
Surprise, surprise, basically he's reiterating my simple argument: why should we give up something that can help us, i.e. automatic checking if all the interfaces are used correctly?

And for the seconds, some  "opinion as a result of ... programming in Lisp in a production environment on non-trivial code"**:
Right off, I can say that the biggest, most glaring thing that causes problems is the lack of static typing. It happens that when the compiler is unable to detect these issues, the end user is left to find them. This can be very potentially damaging to companies. And it is more prominent when you have 100k lines of code, not all of which one can be familiar with.
Lisp takes some steps to help solve these issues. SBCL has very good type inference capabilities, and can warn or error at compile time with type issues. Additionally, Common Lisp allows one to declare and assert argument types, but there’s no guarantee this information can be used. 
And what's SBCL? Let's cite from it's homepage: "Steel Bank Common Lisp (SBCL) is a high performance Common Lisp compiler". What? Even more surprises! Compilers, type inference, assertions? Ok, looks like (at least some of) the LISP hackers came to appreciate the static typing. Who would have thought it?

---
* Lisp Hackers: Marijn Haverbeke - http://lisp-univ-etc.blogspot.de/2012/04/lisp-hackers-marijn-haverbeke.html
** The Perils of Lisp in Production - http://symbo1ics.com/blog/?p=1321