Why version() ?
Nick Sabalausky
a at a.a
Tue Feb 10 16:39:16 PST 2009
"Walter Bright" <newshound1 at digitalmars.com> wrote in message
news:gmsvb8$e1p$1 at digitalmars.com...
> Steven Schveighoffer wrote:
>> 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 ||):
>
> ===============================
{horrid mess of C snipped}
> ===============================
>
> The rest of that file is ALL like that. That one little innocuous change
> opens the door to hell <g>.
>
Ok, but now with D-style version(), that horrid mess becomes this horrid
mess:
======================
version(SUNOS5SIGS)
{
version=SUNOS5SIGSorIRIX5orOSF1orHURDorNETBSD;
version=IRIX5orHPUXorHURDorNETBSD;
}
version(IRIX5)
{
version=SUNOS5SIGSorIRIX5orOSF1orHURDorNETBSD;
version=IRIX5orHPUXorHURDorNETBSD;
}
version(OSF1)
{
version=SUNOS5SIGSorIRIX5orOSF1orHURDorNETBSD;
}
version(HURD)
{
version=SUNOS5SIGSorIRIX5orOSF1orHURDorNETBSD;
version=IRIX5orHPUXorHURDorNETBSD;
}
version(NETBSD)
{
version=SUNOS5SIGSorIRIX5orOSF1orHURDorNETBSD;
version=IRIX5orHPUXorHURDorNETBSD;
}
version(HPUX)
{
version=IRIX5orHPUXorHURDorNETBSD;
}
version(NEED_FIND_LIMIT)
{
version=NEED_FIND_LIMITorUNIX_LIKE;
}
version(UNIX_LIKE)
{
version=NEED_FIND_LIMITorUNIX_LIKE;
}
version(NEED_FIND_LIMITorUNIX_LIKE)
{
version(__STDC__)
typedef void (*handler)(int);
else
typedef void (*handler)();
version(SUNOS5SIGSorIRIX5orOSF1orHURDorNETBSD)
{
static struct sigaction old_segv_act;
version(IRIX5orHPUXorHURDorNETBSD)
static struct sigaction old_bus_act;
}
else
static handler old_segv_handler, old_bus_handler;
version(__STDC__) // This would need an additional workaround due to
syntax issues
{
void GC_set_and_save_fault_handler(handler h)
{
version(SUNOS5SIGSorIRIX5orOSF1orHURDorNETBSD)
{
struct sigaction act;
act.sa_handler = h;
version(none) /* 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(IRIX5orHPUXorHURDorNETBSD)
{
/* 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);
}
}
}
else
{
void GC_set_and_save_fault_handler(h)
handler h;
{
version(SUNOS5SIGSorIRIX5orOSF1orHURDorNETBSD)
{
struct sigaction act;
act.sa_handler = h;
version(none) /* 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(IRIX5orHPUXorHURDorNETBSD)
{
/* 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);
}
}
}
}
======================
Ok, look, we're still knee-deep in hell!
So now you say, "But wait! In D-style, you should change all that to this:"
======================
module MyGC;
version(SUNOS5SIGS) version=SunnyishOS;
version(IRIX5) version=SunnyishOS;
version(HURD) version=SunnyishOS;
version(NETBSD) version=SunnyishOS;
version(NEED_FIND_LIMIT) version=SomethingMeaningful;
version(UNIX_LIKE) version=SomethingMeaningful;
version(SomethingMeaningful)
{
version(__STDC__)
typedef void (*handler)(int);
else
typedef void (*handler)();
// Alternatively, we could "invert" these,
// ie, #include all of them, and have those
// headers take care of their own #ifdef stuff.
// Downside is: all platforms would need all sources.
version(SunnyishOS)
{
version(__STDC__)
{
version(GC_IRIX_THREADS)
public import MyGC_SunnyishOS_STDC_IrixThreads;
else
public import MyGC_SunnyishOS_STDC_NonIrixThreads;
}
else
{
version(GC_IRIX_THREADS)
public import MyGC_SunnyishOS_KR_IrixThreads;
else
public import MyGC_SunnyishOS_KR_NonIrixThreads;
}
}
else version(OSF1)
{
version(__STDC__)
{
version(GC_IRIX_THREADS)
public import MyGC_OSF1_STDC_IrixThreads;
else
public import MyGC_OSF1_STDC_NonIrixThreads;
}
else
{
version(GC_IRIX_THREADS)
public import MyGC_OSF1_KR_IrixThreads;
else
public import MyGC_OSF1_KR_NonIrixThreads;
}
}
//etc...
else
{
version(__STDC__)
public import MyGC_MISC_STDC;
else
public import MyGC_MISC_KR;
}
}
-----
module MyGC_SunnyishOS_STDC_IrixThreads;
static struct sigaction old_segv_act;
static struct sigaction old_bus_act;
void GC_set_and_save_fault_handler(handler h)
{
struct sigaction act;
act.sa_handler = h;
/* Was necessary for Solaris 2.3 and very temporary */
/* NetBSD bugs. */
//act.sa_flags = SA_RESTART | SA_NODEFER;
act.sa_flags = SA_RESTART;
(void) sigemptyset(&act.sa_mask);
/* 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);
}
-----
module MyGC_SunnyishOS_KR_NonIrixThreads;
static struct sigaction old_segv_act;
static struct sigaction old_bus_act;
void GC_set_and_save_fault_handler(h)
handler h;
{
struct sigaction act;
act.sa_handler = h;
/* Was necessary for Solaris 2.3 and very temporary */
/* NetBSD bugs. */
//act.sa_flags = SA_RESTART | SA_NODEFER;
act.sa_flags = SA_RESTART;
(void) sigemptyset(&act.sa_mask);
(void) sigaction(SIGSEGV, &act, &old_segv_act);
/* 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);
}
-----
module MyGC_MISC_STDC;
static handler old_segv_handler, old_bus_handler;
void GC_set_and_save_fault_handler(handler h)
{
old_segv_handler = signal(SIGSEGV, h);
version(SIGBUS)
old_bus_handler = signal(SIGBUS, h);
}
======================
To which I reply, "Yes, and in C-style you should do exactly the same:"
======================
// MyGC.h;
#if defined(SUNOS5SIGS) || defined(IRIX5) || defined(HURD) ||
defined(NETBSD)
# define SUNNYISHOS
#endif
#if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
# define SOMETHING_MEANINGFUL
#endif
#ifdef SOMETHING_MEANINGFUL
# ifdef __STDC__
typedef void (*handler)(int);
# else
typedef void (*handler)();
# endif
// Alternatively, we could "invert" these,
// ie, #include all of them, and have those
// headers take care of their own #ifdef stuff.
// Downside is: all platforms would need all sources.
# ifdef SUNNYISHOS
# ifdef __STDC__
# ifdef GC_IRIX_THREADS
# include "MyGC_SunnyishOS_STDC_IrixThreads.h"
# else
# include "MyGC_SunnyishOS_STDC_NonIrixThreads.h"
# endif
# else /*__STDC__*/
# ifdef GC_IRIX_THREADS
# include "MyGC_SunnyishOS_KR_IrixThreads.h"
# else
# include "MyGC_SunnyishOS_KR_NonIrixThreads.h"
# endif
# endif /*__STDC__*/
# else /*SUNNYISHOS*/
# ifdef OSF1
# ifdef __STDC__
# ifdef GC_IRIX_THREADS
# include "MyGC_OSF1_STDC_IrixThreads.h"
# else
# include "MyGC_OSF1_STDC_NonIrixThreads.h"
# endif
# else /*__STDC__*/
# ifdef GC_IRIX_THREADS
# include "MyGC_OSF1_KR_IrixThreads.h"
# else
# include "MyGC_OSF1_KR_NonIrixThreads.h"
# endif
# endif /*__STDC__*/
# else /*OSF1*/
# ifdef(__STDC__)
# include "MyGC_MISC_STDC.h"
# else
# include "MyGC_MISC_KR.h"
# endif
# endif /*OSF1*/
# endif /*SUNNYISHOS*/
#endif /*SOMETHING_MEANINGFUL*/
-----
// MyGC_SunnyishOS_STDC_IrixThreads.h;
static struct sigaction old_segv_act;
static struct sigaction old_bus_act;
void GC_set_and_save_fault_handler(handler h)
{
struct sigaction act;
act.sa_handler = h;
/* Was necessary for Solaris 2.3 and very temporary */
/* NetBSD bugs. */
//act.sa_flags = SA_RESTART | SA_NODEFER;
act.sa_flags = SA_RESTART;
(void) sigemptyset(&act.sa_mask);
/* 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);
}
-----
// MyGC_SunnyishOS_KR_NonIrixThreads.h
static struct sigaction old_segv_act;
static struct sigaction old_bus_act;
void GC_set_and_save_fault_handler(h)
handler h;
{
struct sigaction act;
act.sa_handler = h;
/* Was necessary for Solaris 2.3 and very temporary */
/* NetBSD bugs. */
//act.sa_flags = SA_RESTART | SA_NODEFER;
act.sa_flags = SA_RESTART;
(void) sigemptyset(&act.sa_mask);
(void) sigaction(SIGSEGV, &act, &old_segv_act);
/* 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);
}
-----
// MyGC_MISC_STDC.h
static handler old_segv_handler, old_bus_handler;
void GC_set_and_save_fault_handler(handler h)
{
old_segv_handler = signal(SIGSEGV, h);
version(SIGBUS)
old_bus_handler = signal(SIGBUS, h);
}
======================
And for the record, with the suggested improvements to D's version(), the
"good" D-style can change from this:
======================
module MyGC;
version(SUNOS5SIGS) version=SunnyishOS;
version(IRIX5) version=SunnyishOS;
version(HURD) version=SunnyishOS;
version(NETBSD) version=SunnyishOS;
version(NEED_FIND_LIMIT) version=SomethingMeaningful;
version(UNIX_LIKE) version=SomethingMeaningful;
version(SomethingMeaningful)
{
// ugly junk...
}
// etc...
======================
To this:
======================
module MyGC;
version(SUNOS5SIGS || IRIX5 || HURD || NETBSD)
version=SunnyishOS;
version(NEED_FIND_LIMIT || UNIX_LIKE)
{
// Alternatively, we could blah blah blah...
version(SunnyishOS)
{
version( __STDC__ && GC_IRIX_THREADS) public import
MyGC_SunnyishOS_STDC_IrixThreads;
version( __STDC__ && !GC_IRIX_THREADS) public import
MyGC_SunnyishOS_STDC_NonIrixThreads;
version(!__STDC__ && GC_IRIX_THREADS) public import
MyGC_SunnyishOS_KR_IrixThreads;
version(!__STDC__ && !GC_IRIX_THREADS) public import
MyGC_SunnyishOS_KR_NonIrixThreads;
}
else version(OSF1)
{
version( __STDC__ && GC_IRIX_THREADS) public import
MyGC_OSF1_STDC_IrixThreads;
version( __STDC__ && !GC_IRIX_THREADS) public import
MyGC_OSF1_STDC_NonIrixThreads;
version(!__STDC__ && GC_IRIX_THREADS) public import
MyGC_OSF1_KR_IrixThreads;
version(!__STDC__ && !GC_IRIX_THREADS) public import
MyGC_OSF1_KR_NonIrixThreads;
}
//etc...
else
{
version( __STDC__) public import MyGC_MISC_STDC;
version(!__STDC__) public import MyGC_MISC_KR;
}
}
//etc...
======================
The point is, the current semantics for D's version() are *plenty*
susceptible to most of same versioning mess as C's #if/#ifdef, and in some
cases (such as ||), even worse. With either style, the solution is exactly
the same as any other chunk of messy code: Clean it up! Not only is gimping
the version-control mechanism the wrong solution, it doesn't even solve the
problem anyway.
More information about the Digitalmars-d
mailing list