Erlang/OTP R10B-10 has been released

Richard A. O'Keefe ok@REDACTED
Fri Mar 24 06:07:07 CET 2006


David Hopwood <david.nospam.hopwood@REDACTED> replied
to my observations about conditional compilation.
I always read anything of his that I see with interest and respect,
so it was a little alarming to see that we didn't appear to agree.
	My experience (mainly in C, but not specific to C) is that this
	is not sufficient in practice.  For example, in a recent
	embedded system, I have:
	
	#define ENABLE_CONTROL            1
	#define ENABLE_HEATER             0
	#define ENABLE_HEATER_ALARM       0
	#define ENABLE_UV                 1
	#define ENABLE_ANTISTATIC         1
	
	and so on, for ~89 features.
	
	This does not mean that there are 2^89 combinations of features
	that need to be tested.  The final program is going to have
	*all* remaining features enabled, after any that don't work or
	are redundant have been stripped out.  A test with some features
	disabled is only intended to be a partial test.
	
Fortunately, he and I are not talking about exactly the same thing.

I was talking about feature tests IN CODE AS DELIVERED so that it is
entirely possible that no two customers will be running the same code.
The particular example program I was talking about has now been reduced
to a possible 100,000 variants, and we have determined that most of them
do NOT in fact work.  (That's because just a few of the features interact
badly.)

David Hopwood is talking about temporarily snipping stuff out
DURING DEVELOPMENT AND TESTING.

	There are two main reasons to disable a feature:
	
	 - because it doesn't work. Sometimes this is because the associated
	   hardware doesn't work yet, and sometimes the code doesn't compile or has
	   known bugs that would interfere with testing the rest of the system.
	
	 - because we want to replace it with a mock/stub implementation for testing
	   on a development system rather than on the actual hardware. In some cases the
	   code would not compile on the development system because a needed library
	   is not implemented there.
	
	Note that as well as stubbing out the code that implements it, disabling a
	feature sometimes needs to change code that would use that feature in other
	modules.
	
	While I like the general idea of feature pseudo-functions, I
	think that to be useful as a tool for testing parts of programs
	during development (which is the main thing I use conditional
	compilation for), there must be support for excluding code that
	doesn't compile.
	
There's a big difference here between C and Erlang.
In C, the presence or absence of a declaration in one place
can affect whether or not a later function can be compiled or not.

As long as you DON'T use the preprocessor, that's not true in Erlang.
In delivery mode, you want missing functions to be errors.
But in development mode, it may be enough if the compiler *warns* about
functions that are used or exported but not defined and automatically
plants stubs that raise an exception if called.

Taking the list of reasons in turn:

 * because it doesn't work

    That's a reason for not *calling* code, but not for not *compiling* it.

   * because the hardware doesn't work yet

      Agreed that you don't want to call code that uses hardware that
      doesn't work yet, but it's not clear to me why you wouldn't want
      to *compile* it.  In fact, it might be *essential* to compile it
      to make sure that it doesn't interfere with something else.

   * because the code doesn't compile

      We are not talking about the desirability of #if in C, but in Erlang.
      It's much harder to write code that doesn't compile.  If it
      doesn't compile, I don't want it processed until it *does*, and that
      means that I *don't* want it controlled by an "ENABLE" switch that
      might accidentally be set.

   * because the code has known bugs

     This is a reason not to *call* the code, not a reason not to *compile*
     it.  You want to select test cases using some kind of rule-based thing
     that leaves out things that test bugs you know about until you are
     ready to test that those bugs have gone.

  * because we want to replace it with a mock/stub implementation

    This is the classic multiple implementations of a single interface
    issue.  This is where you want child modules and a configuration
    management system that says "in this configuration use this child,
    in that configuration use that one."

    In effect, the preprocessor does this kind of stuff *BELOW* the
    language level using a very clunky and limited language.  I'm saying
    that it should be done *ABOVE* the language level using some
    reasonable rule-based language.  (Datalog?)

   * because the code would not compile on one system because
     a needed library isn't there.

So we see that

 - test case selection needs to be informed by which tests exercise
   what, so that we don't (deliberately) *run* code that we don't
   intend to, but that doesn't have to mean we don't *compile* it

 - installing the software in different environments may require different
   implementations for some functions &c, which is very little different
   from the features for installation problem.  And this can be done
   by child modules (which we don't have, but could do with) and some
   kind of declarative configuration language.
   



More information about the erlang-questions mailing list