February 10, 2009
Tim M wrote:
> On Wed, 11 Feb 2009 00:28:21 +1300, bobef <bobef@nospam-abv.bg> wrote:
> 
>> I was thinking... what is the point of version() ? It is so inflexible. There is no even version(!...). Why not "static if(version(DMD))" or static if(is(version == DMD))?
>>
>> Regards,
>> bobef
> 
> You could try something like this:
> 
> 
> module Vers;
> 
> template vers(char[] V)
> {
>       mixin("version(" ~ V ~ ")
>       {
>             const bool vers = true;
>       }
>       else
>       {
>             const bool vers = false;
>       }");
> }
> 
> int main()
> {
>       static if(vers!("X86_64"))
>       {
>             long a;
>             pragma(msg, "64 bit");
>       }
>       else
>       {
>             int a;
>             pragma(msg, "32 bit");
>       }
> 
>       a = 2;
> 
>       return a;
> }
> 

You beat me to it.  I actually use this a little here and there.  But honestly, I find that the cases where I just want 'version(X){...}else{...}' far outweigh the cases where I want 'X && Y' or the like.  While it is technically a hack/workaround, I've been perfectly happy with it.

Now, what would be nice, would be if version() could appear in places it currently can't, following a few rules.  In mid-statement, for example, so long as its body is a complete expression.  And then the same for mixin expressions.  Might be daydreaming too much, there.

Imagine though...

template vers (char[] V) {
    const vers = mixin("version("~V~") {true} else {false}") ;
}

Add to that a deep shorthand syntax a la:

template vers (char[] V) = mixin("version("~V~") {true} else {false}") ;

Okay, I'll come down from the clouds now.

-- Chris Nicholson-Sauls
February 10, 2009
bobef wrote:
> I was thinking... what is the point of version() ? It is so
> inflexible. There is no even version(!...). Why not "static
> if(version(DMD))" or static if(is(version == DMD))?

The version statement is designed to be inflexible. It's designed to encourage abstracting and modularizing version differences, rather than encouraging line-by-line differences.

I've used #if/#endif for decades. Over time, it *always* degenerates into an utter rat's nest of nested, incomprehensible complexity (and this includes my own code). For a lovely example of how bad it can get, take a look at the source code to Hans Boehm's garbage collector. I defy anyone to figure it out without running the code through the preprocessor first to see which statements are actually getting compiled.

A far better way to do versioning is to find the abstraction lines separating versions, and put version specific code in separate modules that are then imported. It makes for nice, clean, understandable code.

Static if can be used for version control, but that is not what it's for. Static if is for use inside templates to control code generation based on template parameters, not for producing different versions of the program.


1. Why not version(!feature) ?

Because cognitive studies show that people just don't see the negation. Secondly, when you see things like:

    version (!linux) { ... }

they're almost always wrong. Versions should be positive things, because a version is something that is being build - one doesn't craft a makefile to build a notLinux.

2. version (A || B) can be done as:

    version (A) version=AorB;
    version (B) version=AorB;

3. version (A && B) can be done as:

   version (A) version (B) { ... }

though if you find yourself doing that a lot, I suggest abstracting away the A and B version into its own AandB version.

4. Conditional compilation can be done with version(all) and version(none).

5. Why can't one 'version out' syntax that is not recognized by the compiler?

The problem is that supporting this requires semantic analysis in order to successfully lex and parse the source code. Breaking this will make the lexing and parsing an order of magnitude harder for third party tools to do. If you need to 'comment out' a section of syntactically invalid code, use the /+ ... +/ nesting comment.
February 10, 2009
On Tue, 10 Feb 2009 13:14:24 -0800, Walter Bright wrote:

> The version statement is designed to be inflexible. It's designed to encourage abstracting and modularizing version differences, rather than encouraging line-by-line differences.

I understand and support this view. However, it creates a new problem; code duplication. Is it possible to provide some syntax or technique to avoid having to cut&paste /small/ runs of code lines. Larger sections of code can be separated into functions or modules, but it because problematic when dealing with small sections (a few lines) of code. The overheads of function calling can be an issue.


> 5. Why can't one 'version out' syntax that is not recognized by the compiler?
> 
> The problem is that supporting this requires semantic analysis in order to successfully lex and parse the source code. Breaking this will make the lexing and parsing an order of magnitude harder for third party tools to do.

Agreed, this is a problem. How can it be solved?

The problem is often found when supporting V1 and V2 code in the same source file. The string mixin trick is NOT, repeat NOT, a satisfactory solution. Duplicating (nearly all of a) source file is NOT, repeat NOT, a satisfatory solution.

-- 
Derek Parnell
Melbourne, Australia
skype: derek.j.parnell
February 10, 2009
"Walter Bright" wrote
> bobef wrote:
>> I was thinking... what is the point of version() ? It is so
>> inflexible. There is no even version(!...). Why not "static
>> if(version(DMD))" or static if(is(version == DMD))?
>
> The version statement is designed to be inflexible. It's designed to encourage abstracting and modularizing version differences, rather than encouraging line-by-line differences.
>
> I've used #if/#endif for decades. Over time, it *always* degenerates into an utter rat's nest of nested, incomprehensible complexity (and this includes my own code). For a lovely example of how bad it can get, take a look at the source code to Hans Boehm's garbage collector. I defy anyone to figure it out without running the code through the preprocessor first to see which statements are actually getting compiled.

There can exist a happy medium between the rigid current design and the disaster that is #if.

> 2. version (A || B) can be done as:
>
>     version (A) version=AorB;
>     version (B) version=AorB;

And it would be much nicer NOT to have to do this.  I think your original position of "let's not get into #if hell" has absolutely (and I mean *absolutely*) no merit as an argument against this one change.

Think of code that is versioned around architecture that would look horrendous if you have to do version statements that have all different combinations of stuff.  If I have 5 different architectures to support, I don't want to have to define a module that has 2^5 different version combinations.  On top of that, the way versioning works, you need 2^4 * 5 different statements:

version(A)
{
   version = AorB;
   version = AorC;
   version = AorD;
   version = AorE;
   version = AorBorC;
   version = AorBorD;
   // ad nauseum.
}
version(B)
{
   // oh fun! let's do it again!!!!
   version = AorB;
   version = BorC;
   version = BorD;
   ...
}

When I add another architecture, *gasp* I have to double the statements (to do them now with and without version(F) ), and now I have to do another 2^5 statements for the version(F) block.  Wheee!

Add to this nightmare that I have to worry about syntax errors, or doing stupid shit like:

version(BorA) // whoops, it's spelled AorB stupid!  no compiler error given

All this can be reduced to 0 statements, and 0 headache if the logical || can be used.  This is why we have computers, so we don't have to calculate this stuff.  Please don't make me use my brain and typing skills where a computer is soooo much better.

>
> 3. version (A && B) can be done as:
>
>    version (A) version (B) { ... }

This isn't as bad of a problem as ||, but still could be nicer as the suggested && syntax.  But I'd be ok with having just the ||.

> 5. Why can't one 'version out' syntax that is not recognized by the compiler?
>
> The problem is that supporting this requires semantic analysis in order to successfully lex and parse the source code. Breaking this will make the lexing and parsing an order of magnitude harder for third party tools to do. If you need to 'comment out' a section of syntactically invalid code, use the /+ ... +/ nesting comment.

Just so you know, this is not a solution.  We all know that the main reason people ask for this is to have code that can compile with D1 or D2 using versioning.  /+ .. +/ doesn't help there.

-Steve


February 10, 2009
Derek Parnell wrote:
> On Tue, 10 Feb 2009 13:14:24 -0800, Walter Bright wrote:
> 
>> The version statement is designed to be inflexible. It's designed to encourage abstracting and modularizing version differences, rather than encouraging line-by-line differences.
> 
> I understand and support this view. However, it creates a new problem; code
> duplication. Is it possible to provide some syntax or technique to avoid
> having to cut&paste /small/ runs of code lines. Larger sections of code can
> be separated into functions or modules, but it because problematic when
> dealing with small sections (a few lines) of code. The overheads of
> function calling can be an issue.

I don't think that duplicating a small run of code is a problem. If it's larger than a small run, it can be abstracted into a function (the overhead is not an issue, as small functions are inlined).



>> 5. Why can't one 'version out' syntax that is not recognized by the compiler?
>>
>> The problem is that supporting this requires semantic analysis in order to successfully lex and parse the source code. Breaking this will make the lexing and parsing an order of magnitude harder for third party tools to do.
> 
> Agreed, this is a problem. How can it be solved?
> 
> The problem is often found when supporting V1 and V2 code in the same
> source file. The string mixin trick is NOT, repeat NOT, a satisfactory
> solution.

I agree that the mixin trick is horrific.

> Duplicating (nearly all of a) source file is NOT, repeat NOT, a
> satisfatory solution.

I'm not insensitive to this as I do it myself in maintaining Phobos. It is a problem, but not a huge one. I find that the meld utility (on linux) makes this chore a snap.
February 10, 2009
Steven Schveighoffer wrote:
> "Walter Bright" wrote
>> 2. version (A || B) can be done as:
>>
>>     version (A) version=AorB;
>>     version (B) version=AorB;
> 
> And it would be much nicer NOT to have to do this.

If you find yourself doing that a lot in the code, then I suggest a better solution is to rethink exactly which versions are being produced, and come up with a set of version identifiers, one for each actual version.

> I think your original position of "let's not get into #if hell" has absolutely (and I mean *absolutely*) no merit as an argument against this one change.

The defense submits as Exhibit A just one snippet from Hans Boehm gc's os_dep.c (note all it uses in #if expressions is ||):

===============================
# if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)

#   ifdef __STDC__
        typedef void (*handler)(int);
#   else
        typedef void (*handler)();
#   endif

#   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
    || defined(HURD) || defined(NETBSD)
        static struct sigaction old_segv_act;
#       if defined(IRIX5) || defined(HPUX) \
        || defined(HURD) || defined(NETBSD)
            static struct sigaction old_bus_act;
#       endif
#   else
        static handler old_segv_handler, old_bus_handler;
#   endif

#   ifdef __STDC__
      void GC_set_and_save_fault_handler(handler h)
#   else
      void GC_set_and_save_fault_handler(h)
      handler h;
#   endif
    {
#       if defined(SUNOS5SIGS) || defined(IRIX5)  \
        || defined(OSF1) || defined(HURD) || defined(NETBSD)
          struct sigaction      act;

          act.sa_handler        = h;
#         if 0 /* Was necessary for Solaris 2.3 and very temporary      */
               /* NetBSD bugs.                                          */
            act.sa_flags          = SA_RESTART | SA_NODEFER;
#         else
            act.sa_flags          = SA_RESTART;
#         endif

          (void) sigemptyset(&act.sa_mask);
#         ifdef GC_IRIX_THREADS
                /* Older versions have a bug related to retrieving and  */
                /* and setting a handler at the same time.              */
                (void) sigaction(SIGSEGV, 0, &old_segv_act);
                (void) sigaction(SIGSEGV, &act, 0);
                (void) sigaction(SIGBUS, 0, &old_bus_act);
                (void) sigaction(SIGBUS, &act, 0);
#         else
                (void) sigaction(SIGSEGV, &act, &old_segv_act);
#               if defined(IRIX5) \
                   || defined(HPUX) || defined(HURD) || defined(NETBSD)
                    /* Under Irix 5.x or HP/UX, we may get SIGBUS.      */
                    /* Pthreads doesn't exist under Irix 5.x, so we     */
                    /* don't have to worry in the threads case.         */
                    (void) sigaction(SIGBUS, &act, &old_bus_act);
#               endif
#         endif /* GC_IRIX_THREADS */
#       else
          old_segv_handler = signal(SIGSEGV, h);
#         ifdef SIGBUS
            old_bus_handler = signal(SIGBUS, h);
#         endif
#       endif
    }
# endif /* NEED_FIND_LIMIT || UNIX_LIKE */
===============================

The rest of that file is ALL like that. That one little innocuous change opens the door to hell <g>.

(Disclaimer: I do not mean to throw tomatoes specifically at Hans here, I know Hans personally and I am in awe of his programming knowledge skill. It's just that many developers have worked on that gc, each one layering on another gob of conditional compilation. This result is typical of C code that's been maintained for years, and you'll find a similar mess in my own code. I didn't want to use my own code as the example of hell because that is too easily dismissed as a personal failing of mine, and that professionals wouldn't do that. But they do. C lends itself to and encourages this kind of programming.)

> 
> Think of code that is versioned around architecture that would look horrendous if you have to do version statements that have all different combinations of stuff.  If I have 5 different architectures to support, I don't want to have to define a module that has 2^5 different version combinations.

Is your code really intended to actually build 32 different versions? May I suggest instead building the 5 architecture versions, and using runtime switches for the variants? Or perhaps abstracting the particular features out into separate modules?


> When I add another architecture, *gasp* I have to double the statements (to do them now with and without version(F) ), and now I have to do another 2^5 statements for the version(F) block.  Wheee!

You're right, that is untenable. What I suggest instead is creating a module:

   module PersonalityForF;

with all the oddities for F exported as constants, aliases, types and functions. This makes it easier for the maintenance developer who needs to do G, he knows he's just got to write a PersonalityForG module rather than edit the source code for dozens of other modules that have embedded version stuff. It also eliminates the risk of breakage of those other modules for the other platforms. (When I do a port of my projects to new platform F, I often inadvertently break A and C because the code for A, C and F are all mixed up together.)

I'm currently working on the Mac port, and am encountering exactly these kinds of problems. One bright spot is I abstracted all the platform specific library reading/writing code out into a separate file rather than using any conditional compilation. This has worked out extremely well. No "os_dep.c" disaster file.



>> 5. Why can't one 'version out' syntax that is not recognized by the compiler?
>>
>> The problem is that supporting this requires semantic analysis in order to successfully lex and parse the source code. Breaking this will make the lexing and parsing an order of magnitude harder for third party tools to do. If you need to 'comment out' a section of syntactically invalid code, use the /+ ... +/ nesting comment.
> 
> Just so you know, this is not a solution.  We all know that the main reason people ask for this is to have code that can compile with D1 or D2 using versioning.  /+ .. +/ doesn't help there.

I know, and I have the same issues with Phobos. See my reply to Derek.
February 10, 2009
"Walter Bright" <newshound1@digitalmars.com> wrote in message news:gmsqnh$6qi$1@digitalmars.com...
>
> The version statement is designed to be inflexible. It's designed to encourage abstracting and modularizing version differences, rather than encouraging line-by-line differences.
>
> I've used #if/#endif for decades. Over time, it *always* degenerates into an utter rat's nest of nested, incomprehensible complexity (and this includes my own code). For a lovely example of how bad it can get, take a look at the source code to Hans Boehm's garbage collector. I defy anyone to figure it out without running the code through the preprocessor first to see which statements are actually getting compiled.
>
> A far better way to do versioning is to find the abstraction lines separating versions, and put version specific code in separate modules that are then imported. It makes for nice, clean, understandable code.
>

This strikes me as throwing away the baby with the bathwater. If your code starts degenerating towards a versioning rat's nest, then the solution is to take a moment and refactor it into a larger granularity, not to throw away features that are useful in moderation.

>
> 1. Why not version(!feature) ?
>
> Because cognitive studies show that people just don't see the negation.

Isn't that moreso a case against the ! operator in general? I don't see how "if(!blah)" is any less susceptible to overlooking the ! than "version(!blah)".

> Secondly, when you see things like:
>
>     version (!linux) { ... }
>
> they're almost always wrong. Versions should be positive things, because a version is something that is being build - one doesn't craft a makefile to build a notLinux.
>

True, we don't build to a NotLinux, but we do however build to "everything except platform X". And I don't see how a "LinuxOrMac" (or worse yet, a "LinuxOr_MacAndSomeOtherCharacteristic_") is any more or less of a realistic platform than a "NotLinux".

Also, you didn't respond to the concerns about typos in a version identifier. Can we assume you agree that's a problem?


February 10, 2009
Nick Sabalausky wrote:
> This strikes me as throwing away the baby with the bathwater. If your code starts degenerating towards a versioning rat's nest, then the solution is to take a moment and refactor it into a larger granularity, not to throw away features that are useful in moderation.

True, but that never, ever happens. It's always "I can get my few additions to this rat's nest in and just get it working, and worry about proper abstraction later."

>> 1. Why not version(!feature) ?
>>
>> Because cognitive studies show that people just don't see the negation.
> 
> Isn't that moreso a case against the ! operator in general? I don't see how "if(!blah)" is any less susceptible to overlooking the ! than "version(!blah)".

Yes, you're right, it's both a minor and an inconsistent point, despite it being right <g>.


>> Secondly, when you see things like:
>>
>>     version (!linux) { ... }
>>
>> they're almost always wrong. Versions should be positive things, because a version is something that is being build - one doesn't craft a makefile to build a notLinux.
> 
> True, we don't build to a NotLinux, but we do however build to "everything except platform X".

We do, and they're always wrong. I always find when doing that and porting to another machine that those #if !linux must be reengineered. I have switched entirely over to:

#if Windows
   ...
#elif linux
   ...
#elif __APPLE__
   ...
#else
   assert(0); // fix when adding a new platform
#endif

because otherwise I *miss* sections that need updating when porting to a new platform, and have a bug that needs tracking down.

The point is, when writing portable code, especially code that will be ported by others, you have *no idea* what platforms will fall into the "notLinux" section and what peculiarities those platforms might have. It works much better to have the compiler ding me when it encounters platform specific code that doesn't have a section for the platform I'm compiling for.

> And I don't see how a "LinuxOrMac" (or worse yet, a "LinuxOr_MacAndSomeOtherCharacteristic_") is any more or less of a realistic platform than a "NotLinux".

Based on my experience porting code, LinuxOrMac is a far better solution (i.e. faster to code, faster to port, fewer bugs) than notWindows.


> Also, you didn't respond to the concerns about typos in a version identifier. Can we assume you agree that's a problem? 

It's a problem without a solution unless you propose adding some sort of declaration syntax for all the version identifiers.
February 10, 2009
I see your points, although I don't quite agree. Programmers will continue to do stupid things, even if it hurts. And in these cases, having an "intentionally hard to use" version-statement might increase the overall mess even further.

But what do you say about the possibility of uncatched typos? (the "version(linxu) {" example)
February 10, 2009
On Wed, 11 Feb 2009 01:33:12 +0300, Walter Bright <newshound1@digitalmars.com> wrote:

> Steven Schveighoffer wrote:
>> "Walter Bright" wrote
>>> 2. version (A || B) can be done as:
>>>
>>>     version (A) version=AorB;
>>>     version (B) version=AorB;
>>  And it would be much nicer NOT to have to do this.
>
> If you find yourself doing that a lot in the code, then I suggest a better solution is to rethink exactly which versions are being produced, and come up with a set of version identifiers, one for each actual version.
>
>> I think your original position of "let's not get into #if hell" has absolutely (and I mean *absolutely*) no merit as an argument against this one change.
>
> The defense submits as Exhibit A just one snippet from Hans Boehm gc's os_dep.c (note all it uses in #if expressions is ||):
>
> ===============================
> # if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
>
> #   ifdef __STDC__
>          typedef void (*handler)(int);
> #   else
>          typedef void (*handler)();
> #   endif
>
> #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
>      || defined(HURD) || defined(NETBSD)
>          static struct sigaction old_segv_act;
> #       if defined(IRIX5) || defined(HPUX) \
>          || defined(HURD) || defined(NETBSD)
>              static struct sigaction old_bus_act;
> #       endif
> #   else
>          static handler old_segv_handler, old_bus_handler;
> #   endif
>
> #   ifdef __STDC__
>        void GC_set_and_save_fault_handler(handler h)
> #   else
>        void GC_set_and_save_fault_handler(h)
>        handler h;
> #   endif
>      {
> #       if defined(SUNOS5SIGS) || defined(IRIX5)  \
>          || defined(OSF1) || defined(HURD) || defined(NETBSD)
>            struct sigaction      act;
>
>            act.sa_handler        = h;
> #         if 0 /* Was necessary for Solaris 2.3 and very temporary      */
>                 /* NetBSD bugs.                                          */
>              act.sa_flags          = SA_RESTART | SA_NODEFER;
> #         else
>              act.sa_flags          = SA_RESTART;
> #         endif
>
>            (void) sigemptyset(&act.sa_mask);
> #         ifdef GC_IRIX_THREADS
>                  /* Older versions have a bug related to retrieving and  */
>                  /* and setting a handler at the same time.              */
>                  (void) sigaction(SIGSEGV, 0, &old_segv_act);
>                  (void) sigaction(SIGSEGV, &act, 0);
>                  (void) sigaction(SIGBUS, 0, &old_bus_act);
>                  (void) sigaction(SIGBUS, &act, 0);
> #         else
>                  (void) sigaction(SIGSEGV, &act, &old_segv_act);
> #               if defined(IRIX5) \
>                     || defined(HPUX) || defined(HURD) || defined(NETBSD)
>                      /* Under Irix 5.x or HP/UX, we may get SIGBUS.      */
>                      /* Pthreads doesn't exist under Irix 5.x, so we     */
>                      /* don't have to worry in the threads case.         */
>                      (void) sigaction(SIGBUS, &act, &old_bus_act);
> #               endif
> #         endif /* GC_IRIX_THREADS */
> #       else
>            old_segv_handler = signal(SIGSEGV, h);
> #         ifdef SIGBUS
>              old_bus_handler = signal(SIGBUS, h);
> #         endif
> #       endif
>      }
> # endif /* NEED_FIND_LIMIT || UNIX_LIKE */
> ===============================
>

Ok, I've imagined that Boehm GC is written in D and went into a trouble of rewriting the #if/else/endif stuf into versioning blocks:


version(NEED_FIND_LIMIT) version = NEED_FIND_LIMIT_or_UNIT_LIKE;
version(UNIX_LIKE) version = NEED_FIND_LIMIT_or_UNIT_LIKE;

version(NEED_FIND_LIMIT_or_UNIT_LIKE) {

   version (__STDC__) {
       typedef void (*handler)(int);
   } else {
       typedef void (*handler)();
   }

	version (SUNOS5SIGS) version = SUNOS5SIGS_or_IRIX5_or_OSF1_or_HURD_or_NETBSD;
	version (IRIX5) version = SUNOS5SIGS_or_IRIX5_or_OSF1_or_HURD_or_NETBSD;
	version (OSF1) version = SUNOS5SIGS_or_IRIX5_or_OSF1_or_HURD_or_NETBSD;
	version (HURD) version = SUNOS5SIGS_or_IRIX5_or_OSF1_or_HURD_or_NETBSD;
	version (NETBSD) version = SUNOS5SIGS_or_IRIX5_or_OSF1_or_HURD_or_NETBSD;
	
	version (IRIX5) version = IRIX5_or_HPUX_or_HURD_or_NETBSD;
	version (HPUX) version = IRIX5_or_HPUX_or_HURD_or_NETBSD;
	version (HURD) version = IRIX5_or_HPUX_or_HURD_or_NETBSD;
	version (NETBSD) version = IRIX5_or_HPUX_or_HURD_or_NETBSD;
	
	version (SUNOS5SIGS_or_IRIX5_or_OSF1_or_HURD_or_NETBSD) {
       static struct sigaction old_segv_act;
           version (IRIX5_or_HPUX_or_HURD_or_NETBSD) {
           static struct sigaction old_bus_act;
       }
   } else {
       static handler old_segv_handler, old_bus_handler;
   }

version (__STDC__) {
     void GC_set_and_save_fault_handler(handler h)
} else {
     void GC_set_and_save_fault_handler(h)
     handler h;
}
   {
      version(SUNOS5SIGS_or_IRIX5_or_OSF1_or_HURD_or_NETBSD) {
         struct sigaction      act;

         act.sa_handler        = h;
         version(false) { /* Was necessary for Solaris 2.3 and very temporary      */
           /* NetBSD bugs.                                          */
           act.sa_flags          = SA_RESTART | SA_NODEFER;
         } else {
           act.sa_flags          = SA_RESTART;
         }

         (void) sigemptyset(&act.sa_mask);
         version(GC_IRIX_THREADS) {
               /* Older versions have a bug related to retrieving and  */
               /* and setting a handler at the same time.              */
               (void) sigaction(SIGSEGV, 0, &old_segv_act);
               (void) sigaction(SIGSEGV, &act, 0);
               (void) sigaction(SIGBUS, 0, &old_bus_act);
               (void) sigaction(SIGBUS, &act, 0);
         } else {
               (void) sigaction(SIGSEGV, &act, &old_segv_act);
               version (IRIX5_or_HPUX_or_HURD_or_NETBSD) {
                   /* Under Irix 5.x or HP/UX, we may get SIGBUS.      */
                   /* Pthreads doesn't exist under Irix 5.x, so we     */
                   /* don't have to worry in the threads case.         */
                   (void) sigaction(SIGBUS, &act, &old_bus_act);
               }
         }
     } else {
        old_segv_handler = signal(SIGSEGV, h);
        version (SIGBUS) {
           old_bus_handler = signal(SIGBUS, h);
        }
     }
  }
}

Does it look any better? No way! Besides, C/C++/C# style directives so much more powerful that I'd happily exchange version them just to avoid code duplication hell in my source code files.

> The rest of that file is ALL like that. That one little innocuous change opens the door to hell <g>.
>
> (Disclaimer: I do not mean to throw tomatoes specifically at Hans here, I know Hans personally and I am in awe of his programming knowledge skill. It's just that many developers have worked on that gc, each one layering on another gob of conditional compilation. This result is typical of C code that's been maintained for years, and you'll find a similar mess in my own code. I didn't want to use my own code as the example of hell because that is too easily dismissed as a personal failing of mine, and that professionals wouldn't do that. But they do. C lends itself to and encourages this kind of programming.)
>
>>  Think of code that is versioned around architecture that would look horrendous if you have to do version statements that have all different combinations of stuff.  If I have 5 different architectures to support, I don't want to have to define a module that has 2^5 different version combinations.
>
> Is your code really intended to actually build 32 different versions? May I suggest instead building the 5 architecture versions, and using runtime switches for the variants? Or perhaps abstracting the particular features out into separate modules?
>
>
>> When I add another architecture, *gasp* I have to double the statements (to do them now with and without version(F) ), and now I have to do another 2^5 statements for the version(F) block.  Wheee!
>
> You're right, that is untenable. What I suggest instead is creating a module:
>
>     module PersonalityForF;
>
> with all the oddities for F exported as constants, aliases, types and functions. This makes it easier for the maintenance developer who needs to do G, he knows he's just got to write a PersonalityForG module rather than edit the source code for dozens of other modules that have embedded version stuff. It also eliminates the risk of breakage of those other modules for the other platforms. (When I do a port of my projects to new platform F, I often inadvertently break A and C because the code for A, C and F are all mixed up together.)
>
> I'm currently working on the Mac port, and am encountering exactly these kinds of problems. One bright spot is I abstracted all the platform specific library reading/writing code out into a separate file rather than using any conditional compilation. This has worked out extremely well. No "os_dep.c" disaster file.
>
>

The story is not about different functionality on different platforms but rather about a common code which is 98% the same on all the platforms and is different in *small* details. For example, I'd like to make my library D1 and D2 compatible. Do you suggest me to maintain 2 different libraries? This is ridiculous, and that's why there is no Tango2 release yet - there is *no* point in supporting such a large library as Tango (or DWT) for two language versions without a sane versioning mechanism.

>
>>> 5. Why can't one 'version out' syntax that is not recognized by the compiler?
>>>
>>> The problem is that supporting this requires semantic analysis in order to successfully lex and parse the source code. Breaking this will make the lexing and parsing an order of magnitude harder for third party tools to do. If you need to 'comment out' a section of syntactically invalid code, use the /+ ... +/ nesting comment.
>>  Just so you know, this is not a solution.  We all know that the main reason people ask for this is to have code that can compile with D1 or D2 using versioning.  /+ .. +/ doesn't help there.
>
> I know, and I have the same issues with Phobos. See my reply to Derek.