Topic: Article for comp.std.c++: Eliminating #ifdef: if const


Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/02/22
Raw View
shankar@mti.mti.sgi.com (Shankar Unni) writes:

>Often, an #ifdef covers just a small part of an expression that may be
>different between different environments, or some such small differences:
>
>   if (some condition) {
>#ifdef SOMEIMPL
> if (some other condition) {
>#endif /* SOMEIMPL */
> /* code */
> /* code */
> /* code */
>#ifdef SOMEIMPL
> }
>#endif /* SOMEIMPL */
>   }

But with `if const', your 11 lines of code could be rewritten as either

 if (some condition) {
  if (SOMEIMPL && some other condition) {
   /* code */
   /* code */
   /* code */
  }
 }

 (7 lines of code)

or, if `some other condition' won't compile on other implementations, as

 if (some condition) {
  bool some_other_condition = true;
  if const (SOMEIMPL) {
   some_other_condition = some other condition;
  }
  if (other_condition) {
   /* code */
   /* code */
   /* code */
  }
 }

 (11 lines of code)

Both of these solutions have the advantage that the test for `SOMEIMPL'
occurs only once, so things will be easier if you later have to change it to
`SOMEIMPL || SOMEOTHERIMPL'.

>Duplicating all the code so that each half is precisely correct in its {}
>matching is both tedious and error-prone (trying to verify that both parts
>of the expression are fixed).

But fortunately as shown above it would not be required.

>Also, the #ifdefs serve a purpose in pointing out the fact that this piece
>of code is system-dependent.  The syntax you propose hides its warts rather
>too well, and make it easy for a reader to miss the significant piece of
>information that this area of code is system-dependent.

True, but a convention of using upper-case for SOMEIMPL and similar constants
would make such tests stand out.

--
Fergus Henderson              WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au               PGP: finger fjh@128.250.37.3
---
[ To submit articles: try just posting with your news-reader.
                      If that fails, use mailto:std-c++@ncar.ucar.edu
  FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html
  Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu.
]





Author: maney@mcs.com (Martin J. Maney)
Date: 1996/02/23
Raw View
Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
> shankar@mti.mti.sgi.com (Shankar Unni) writes:

> >Often, an #ifdef covers just a small part of an expression that may be
> >different between different environments, or some such small differences:
> >
> >   if (some condition) {
> >#ifdef SOMEIMPL
> > if (some other condition) {
> >#endif /* SOMEIMPL */
> > /* code */
> > /* code */
> > /* code */
> >#ifdef SOMEIMPL
> > }
> >#endif /* SOMEIMPL */
> >   }

> But with `if const', your 11 lines of code could be rewritten as either

>  if (some condition) {
>   if (SOMEIMPL && some other condition) {
>    /* code */
>    /* code */
>    /* code */
>   }
>  }

>  (7 lines of code)

Of course it's a little unfair to pick on the specific features of the
example, but I can no longer resist the temptation to point out that all
of these are simply awful ways to deal with this sort of target
dependency.  What you truly want in these cases is to replace the
platform-dependent hackery with

  if (implementation_defined_test())
  {
      ...
  }

And let implementation_defined_test() be defined in whatever place you
like to collect portability [sic] stuff.  In C one might have to choose
between a function-like macro that could be unsafe and a function that
might be too costly, but in C++ you can have hte best of both worlds if
you make it an inline function.

Again: I realize there are other applications for the proposed idea; I
encourage its supporters to present them and make a better case for this
feature.  But this example strikes me as an argument _against_ the
feature on the grounds that it encourages what I am happy to call a
simply awful coding style.

> Both of these solutions have the advantage that the test for `SOMEIMPL'
> occurs only once, so things will be easier if you later have to change it to
> `SOMEIMPL || SOMEOTHERIMPL'.

Ditto.  Plus the advantage that if this condition is tested for elsewhere
- and if it isn't now, what are the odds it will be before the program is
finally retired from service? - the inline function, like the ugly C
macro, will at least have a chance of getting the change into every piece
of code that uses it, if only the dependencies are setup correctly.  ;-)

> >Duplicating all the code so that each half is precisely correct in its {}
> >matching is both tedious and error-prone (trying to verify that both parts
> >of the expression are fixed).

> But fortunately as shown above it would not be required.

Ditto.

> >Also, the #ifdefs serve a purpose in pointing out the fact that this piece
> >of code is system-dependent.  The syntax you propose hides its warts rather
> >too well, and make it easy for a reader to miss the significant piece of
> >information that this area of code is system-dependent.

> True, but a convention of using upper-case for SOMEIMPL and similar constants
> would make such tests stand out.

I will concede that the inline function hides this as well as you want to
- I used a long, blatant name in my example for precisely this reason.
But then again, if you don't have to worry about writing the details of
the target-dependent code all over the place, what difference does it make
how visible it is or isn't in use?

[ To submit articles: Try just posting with your newsreader.
        If that fails, use mailto:std-c++@ncar.ucar.edu
  FAQ:    http://reality.sgi.com/employees/austern_mti/std-c++/faq.html
  Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Mark Russell <M.T.Russell@ukc.ac.uk>
Date: 1996/02/16
Raw View
Subject: Eliminating #ifdef: if const

Here's an idea I had for a non-preprocessor replacement for #if and  #ifdef.

 if const (<expr>) { <stuff> }

`if const' is a compile time version of `if'.  <expr> is a constant
expression which is convertible to bool.  If it yields true, <stuff>
is processed as normal.  Otherwise <stuff> is parsed into tokens, but
ignored except for counting { and } nesting.  <stuff> is anything that
can appear inside a namespace block.  `if const' does not introduce a
new scope.

The following is also legal, with the obvious meaning:

 if const (<expr>) { <stuff> } else const { <other stuff> }

There are also a number of compile-time pseudo-functions (I hesitate
to call them pragmas):

 bool #os_version(const char* str)

  os version (uname -r) at or later than str

 bool #os_name(const char *str)

  os name (uname -s) is str

 bool #compiler_name(const char *)
 bool #compiler_version(const char*)

  Same tests for the compiler

 bool #header_exists(const char* path)

  Would `#include <path>' succeed?

 bool #have_test(const char* varname)

  Would #varname(str) work (this would be useful to
  allow testing for implementation defined tests.

Using these you could do things like this:

 // Are we running IRIX 5.3
 const bool using_irix_53 = #os_name("IRIX") &&
       #os_version("5.3") && !#os_version("5.4")

 if const (using_irix_53) {
  // Do some stuff needed just for IRIX 5.3
 }

 if const (#compiler("g++")) {
  // Do some g++ stuff
 }

 if const (#header_exists("sys/frobnitz9000.h")) {
  #include "sys/frobnitz9000.h"
  // Do stuff for the Frobnitz 9000
 }

 if const (#have_test("extension")) {
  const bool have_foo_extension = #extension_exists("foo");
 }
 else const {
  const bool have_foo_extension = false;
 }

 if const (have_foo_extension) {
  // Stuff using the `foo' extension
 }

With this I could personally stop using the preprocessor for anything
except #include.  If `include' (as described in D&E) is also
implemented, I could stop using the preprocessor altogether, which
would be nice.

I realise this is too late for the upcoming version of the standard,
but I think it would be a useful thing for a subsequent version.

Comments?

Mark Russell
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy is
  in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]





Author: tony@online.tmx.com.au (Tony Cook)
Date: 1996/02/20
Raw View
Mark Russell (M.T.Russell@ukc.ac.uk) wrote:
: Subject: Eliminating #ifdef: if const

: Here's an idea I had for a non-preprocessor replacement for #if and  #ifdef.

:  if const (<expr>) { <stuff> }

: `if const' is a compile time version of `if'.  <expr> is a constant
: expression which is convertible to bool.  If it yields true, <stuff>
: is processed as normal.  Otherwise <stuff> is parsed into tokens, but
: ignored except for counting { and } nesting.  <stuff> is anything that
: can appear inside a namespace block.  `if const' does not introduce a
: new scope.

: The following is also legal, with the obvious meaning:

:  if const (<expr>) { <stuff> } else const { <other stuff> }

: There are also a number of compile-time pseudo-functions (I hesitate
: to call them pragmas):

:  bool #os_version(const char* str)

:   os version (uname -r) at or later than str

:  bool #os_name(const char *str)

:   os name (uname -s) is str

These would require mechanisms to supply operating system parameters
to the compiler - besides, a module compiled for one operating
system can sometimes be linked into an executable for another on
(some 16-bit DOS modules can be used in a Windows program).

OS/2 FAPI programs can run under DOS, OS/2 or Windows NT.

:  bool #compiler_name(const char *)
:  bool #compiler_version(const char*)

:   Same tests for the compiler

These might be nice.

: Using these you could do things like this:

:  // Are we running IRIX 5.3
:  const bool using_irix_53 = #os_name("IRIX") &&
:        #os_version("5.3") && !#os_version("5.4")

:  if const (using_irix_53) {
:   // Do some stuff needed just for IRIX 5.3
:  }

:  if const (#compiler("g++")) {
:   // Do some g++ stuff
:  }

:  if const (#header_exists("sys/frobnitz9000.h")) {
:   #include "sys/frobnitz9000.h"
:   // Do stuff for the Frobnitz 9000
:  }

Doesn't this bind the preprocess and compiler closer together?  For
the compilation stages in the WP won't the #include occur in stage 4
and the if const in stage 7?

: With this I could personally stop using the preprocessor for anything
: except #include.  If `include' (as described in D&E) is also
: implemented, I could stop using the preprocessor altogether, which
: would be nice.

What's the difference between what you've specified and the
preprocessor (other than different syntax?)

--
        Tony Cook - tony@online.tmx.com.au
                    100237.3425@compuserve.com
---
[ To submit articles: Try just posting with your newsreader.  If that fails,
                      use mailto:std-c++@ncar.ucar.edu
  FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html
  Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
  Comments? mailto:std.c++-request@ncar.ucar.edu
]