#ifdef considered harmful (was: DData)

Alastair Reid alastair at reid-consulting-uk.ltd.uk
Fri Apr 16 15:35:30 EDT 2004


On Friday 16 April 2004 13:25, Wolfgang Jeltsch wrote:
> The very big problem with the preprocessor approach is,
> in my opinion, that it's awkward to add a new platform.  With Robert's
> approach you just add some new files and don't touch the existing code. 
> With the preprocessor approach you need write access to the source code of
> the library in question, I'd say.

I find that it works a little differently in practice (when writing C, at 
least):

1) You write the code for one platform.

2) To add a second platform, you refactor the code by designing
   a portable interface to the functionality of the two platforms
   and splitting the code into a portable top half and two 
   platform specific bottom halves.

   [In practice, the first two steps are often combined since many
   of us develop for two platforms at once.]

3) You add a few minor variations on the original platforms with little
   effort.

   For very closely related platforms (Win98 and Win2K, Debian and Redhat,
   versions 3.4 and 3.5 of <whatever>), you might have just one or two lines
   of changes.  Suppose you need to change just one line out of 100 lines
   of code, do you further subdivide the platform-specific module,
   do you use ifdef or do you cut and paste 100 lines of code.

   [Complication: the person doing the port might not have access to
   the original platform so they can't test the modified code.  No problem if
   you're writing a completely fresh implementation but a major issue if
   you have to refactor an existing implementation.]

4) You try to port it to a less familiar platform: Mac, HPUX, etc. which
   views the world from a different angle from Unix and Windows and have
   to change the design of the portable interface to all the implementations.
   This requires that you change the code in all implementations.

   [Complication: again, you may not have access to the other platforms.]

Refactoring the code into multiple modules can play a part in porting code but 
conditional compilation plays an important role too.  In particular, if you 
find yourself changing code that you can't test, you can use conditional 
compilation to leave the bulk of the code unchanged so that simple tools 
(e.g., diff) can help you hand-check the changes you can't check.

Of course, we don't see this in Haskell much but that's because we don't try 
very hard to support multiple versions of a library...

--
Alastair Reid


More information about the Libraries mailing list