www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - remove keywords

reply mandel <oh no.es> writes:
A proposal in a nutshell:

- removal of the keywords "unittest, "version" and similar.

- replaced by global compile time variables.

- "dmd -<name>=<value>" to set them. Variables not found result in 
compiler warnings

- "dmd -list version*" or similar to list all global variable names with 
prefix "version"

-> less keywords, more powerfull control (use in boolean expressions), 
more native syntax, easier to understand

Ideas? Problems? Objections?

btw.:
bool enableXYZ;

if(enableXFZ) import foo.Bar;

..might be hairy to implement?
Dec 07 2007
next sibling parent reply Denton Cockburn <diboss hotmail.com> writes:
On Fri, 07 Dec 2007 08:55:45 +0000, mandel wrote:

 A proposal in a nutshell:
 
 - removal of the keywords "unittest, "version" and similar.
 
 - replaced by global compile time variables.
 
 - "dmd -<name>=<value>" to set them. Variables not found result in
 compiler warnings
 
 - "dmd -list version*" or similar to list all global variable names with
 prefix "version"
 
 -> less keywords, more powerfull control (use in boolean expressions),
 more native syntax, easier to understand
 
 Ideas? Problems? Objections?
 
 btw.:
 bool enableXYZ;
 
 if(enableXFZ) import foo.Bar;
 
 ..might be hairy to implement?

seems like a rather big change. Do you really have a big problem with the current method? or you just think this is better? I'd rather forgo a big change if the current method isn't painful (it's not).
Dec 07 2007
next sibling parent reply mandel <oh no.es> writes:
Yes, it would be a big change.
But the code changes would be trivial imho.

I just think it's better (consinstent) to do it this way for the 
mentioned reasons.
For example, one of the motivations was:

if(bar)
{
  version(Foo)
  {
     /**/
  }
}

I would rather like to write:

if(bar && Foo)
{
  /**/
}

There are workarounds, but none of them is as nice as the native/proposed 
solution above.

On Fri, 07 Dec 2007 09:16:02 +0000, Denton Cockburn wrote:

 On Fri, 07 Dec 2007 08:55:45 +0000, mandel wrote:

 seems like a rather big change.
 Do you really have a big problem with the current method? or you just
 think this is better?
 
 I'd rather forgo a big change if the current method isn't painful (it's
 not).

Dec 07 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
mandel wrote:
 For example, one of the motivations was:
 
 if(bar)
 {
   version(Foo)
   {
      /**/
   }
 }
 
 I would rather like to write:
 
 if(bar && Foo)
 {
   /**/
 }

The version statement is limited in that you cannot do !foo or foo&&bar||baz. Rather than a bug, that is deliberate. I've seen a lot of code that, over the years, accumulated detritus like: #if FOO || BAR>0x1234 && BAZ && !HACK These tend to snarl themselves into such a rat's nest of conditionals the only way to figure out which lines actually got compiled was to examine the preprocessor output. (Another consequence of these is that, inevitably, the various conditionals were WRONG as they were layered on by people who didn't really understand the code.) So, by limiting the version statement, the idea is to encourage the programmer to think in terms of distinct versions being generated, and then code in terms of those distinct versions - each of those versions having a name.
Dec 07 2007
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:fjb8c6$2nqs$1 digitalmars.com...
 The version statement is limited in that you cannot do !foo or 
 foo&&bar||baz. Rather than a bug, that is deliberate. I've seen a lot of 
 code that, over the years, accumulated detritus like:

     #if FOO || BAR>0x1234 && BAZ && !HACK

 These tend to snarl themselves into such a rat's nest of conditionals the 
 only way to figure out which lines actually got compiled was to examine 
 the preprocessor output. (Another consequence of these is that, 
 inevitably, the various conditionals were WRONG as they were layered on by 
 people who didn't really understand the code.)

 So, by limiting the version statement, the idea is to encourage the 
 programmer to think in terms of distinct versions being generated, and 
 then code in terms of those distinct versions - each of those versions 
 having a name.

You tell me which is more readable: version(linux || darwin || bsd) version = UseDlfcn; else version = UseDLLs; vs. version(linux) version = UseDlfcn; else version(darwin) version = UseDlfcn; else version(bsd) version = UseDlfcn; else version = UseDLLs; It only gets worse when you actually *need* complex versioning, and when the contents of those version blocks become more than trivial. Yes, you can define intermediate versions like I've done here, but even that becomes tedious and hard to read.
Dec 07 2007
next sibling parent Sean Kelly <sean f4.ca> writes:
Jarrett Billingsley wrote:
 "Walter Bright" <newshound1 digitalmars.com> wrote in message 
 news:fjb8c6$2nqs$1 digitalmars.com...
 The version statement is limited in that you cannot do !foo or 
 foo&&bar||baz. Rather than a bug, that is deliberate. I've seen a lot of 
 code that, over the years, accumulated detritus like:

     #if FOO || BAR>0x1234 && BAZ && !HACK

 These tend to snarl themselves into such a rat's nest of conditionals the 
 only way to figure out which lines actually got compiled was to examine 
 the preprocessor output. (Another consequence of these is that, 
 inevitably, the various conditionals were WRONG as they were layered on by 
 people who didn't really understand the code.)

 So, by limiting the version statement, the idea is to encourage the 
 programmer to think in terms of distinct versions being generated, and 
 then code in terms of those distinct versions - each of those versions 
 having a name.

You tell me which is more readable: version(linux || darwin || bsd) version = UseDlfcn; else version = UseDLLs; vs. version(linux) version = UseDlfcn; else version(darwin) version = UseDlfcn; else version(bsd) version = UseDlfcn; else version = UseDLLs; It only gets worse when you actually *need* complex versioning, and when the contents of those version blocks become more than trivial. Yes, you can define intermediate versions like I've done here, but even that becomes tedious and hard to read.

There's always static if. Sean
Dec 07 2007
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Jarrett Billingsley" wrote
 You tell me which is more readable:

 version(linux || darwin || bsd)
    version = UseDlfcn;
 else
    version = UseDLLs;

 vs.

 version(linux)
    version = UseDlfcn;
 else version(darwin)
    version = UseDlfcn;
 else version(bsd)
    version = UseDlfcn;
 else
    version = UseDLLs;

First one is more readable. I think maybe the version syntax could be expanded to mean 'or' with commas. i.e. version(linux, darwin, bsd) And forget any other logic syntax (ands, less than, etc). I believe the current method does a good job of preventing convoluted version statements, but I think the 'or' is a very common requirement, and does not detract from the readability. -Steve
Dec 07 2007
prev sibling next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Jarrett Billingsley wrote:
 You tell me which is more readable:
 
 version(linux || darwin || bsd)
     version = UseDlfcn;
 else
     version = UseDLLs;
 
 vs.
 
 version(linux)
     version = UseDlfcn;
 else version(darwin)
     version = UseDlfcn;
 else version(bsd)
     version = UseDlfcn;
 else
     version = UseDLLs;

I'm going to say the latter is more readable, especially when under each os there are a series of version declarations. The former approach is used by, for example, the Hans Boehm garbage collector, and I have found it very difficult to follow.
 It only gets worse when you actually *need* complex versioning, and when the 
 contents of those version blocks become more than trivial.  Yes, you can 
 define intermediate versions like I've done here, but even that becomes 
 tedious and hard to read. 

When the versioning becomes complex, there are alternative ways of managing it. One way that works well is to factor out version differences into version specific modules, with a general purpose api to those modules. Yes, this is more work, but when I've done it the results have been well worthwhile.
Dec 07 2007
prev sibling parent Christopher Wright <dhasenan gmail.com> writes:
Jarrett Billingsley wrote:
 "Walter Bright" <newshound1 digitalmars.com> wrote in message 
 news:fjb8c6$2nqs$1 digitalmars.com...
 The version statement is limited in that you cannot do !foo or 
 foo&&bar||baz. Rather than a bug, that is deliberate. I've seen a lot of 
 code that, over the years, accumulated detritus like:

     #if FOO || BAR>0x1234 && BAZ && !HACK

 These tend to snarl themselves into such a rat's nest of conditionals the 
 only way to figure out which lines actually got compiled was to examine 
 the preprocessor output. (Another consequence of these is that, 
 inevitably, the various conditionals were WRONG as they were layered on by 
 people who didn't really understand the code.)

 So, by limiting the version statement, the idea is to encourage the 
 programmer to think in terms of distinct versions being generated, and 
 then code in terms of those distinct versions - each of those versions 
 having a name.

You tell me which is more readable: version(linux || darwin || bsd) version = UseDlfcn; else version = UseDLLs; vs. version(linux) version = UseDlfcn; else version(darwin) version = UseDlfcn; else version(bsd) version = UseDlfcn; else version = UseDLLs; It only gets worse when you actually *need* complex versioning, and when the contents of those version blocks become more than trivial. Yes, you can define intermediate versions like I've done here, but even that becomes tedious and hard to read.

I've dealt with production code -- a mere 5k line project -- that was ported manually to four operating systems (Linux, HPUX, Darwin, and I think FreeBSD). My task was to convert it to use autotools. Ugly. Horrible. Terrible. I wanted to find the coders and shoot them. You're recommending an autoconf-like system, basically. Which I commend. But then you just code for version(has_feature). And your config file might be relatively large, with several entries for each OS. So you'd have: // dll stuff version(linux || darwin || bsd) version = UseDlfcn; else version = UseDll; // socket stuff ... I would prefer: version(linux) version = UseDlfcn; // ... version(darwin)... It works with the current syntax, and it is equally organized. It's easier to see, given a platform, what versions you have defined. On the other hand, it's a bit harder to see whether a particular version is defined.
Dec 07 2007
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2007-12-07 05:47:36 -0500, Walter Bright <newshound1 digitalmars.com> said:

 So, by limiting the version statement, the idea is to encourage the 
 programmer to think in terms of distinct versions being generated, and 
 then code in terms of those distinct versions - each of those versions 
 having a name.

I've come into a situation where I'll probably have to take the bloat from the code and transfer it to the build process because of this limitation. Apple's C/C++/Obj-C headers all use the following idiom to create single header files adapted to the target version of Mac OS X you wish to use: #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 // Mac OS X 10.3 specific functions prototypes #endif #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 // Mac OS X 10.4 specific functions prototypes #endif #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 // Mac OS X 10.5 specific functions prototypes #endif Then you only need to set MAC_OS_X_VERSION_MAX_ALLOWED to the actual version number and you instantly have headers limited to the version your application is targeting. (Or if you don't you get headers for the latest version.) The only way I see to replicate that in D when converting Apple headers is to use: version (MAC_OS_X_VERSION_10_3) { // Mac OS X 10.3 specific functions prototypes. } version (MAC_OS_X_VERSION_10_4) { // Mac OS X 10.4 specific functions prototypes. } version (MAC_OS_X_VERSION_10_5) { // Mac OS X 10.5 specific functions prototypes. } This is inconvenient (and error prone) because if you're going to import a module with these version flags in your program, you then need to define when version flags for each previous version of the OS; and the number of symbols to define will always go in increasing. If you could just write: version (MAC_OS_X_VERSION >= 10.3) it'd make things much easier. Even better would be: version (MAC_OS_X_VERSION <= 10.1 && MAC_OS_X_VERSION > 10.4) to indicate a function added at version 10.1 and removed in 10.4. To do that with my current system, it'd read: version (MAC_OS_X_VERSION_10_3) { } else version (MAC_OS_X_VERSION_10_1) { // some functions added in Mac OS X 10.1 but removed in 10.4. } which isn't that clear either. By the way, I know I could use simply a version number flag and write: version (1) { } version (2) { } version (3) { } But then it'll prevent anyone from using version numbers for their own application when using ported headers. Now that I'm thinking about it, the simplest solution probably lies in using version to declare some constants in a module mimicking AvailabilityMacros.h, then using those constants with static ifs.=. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 07 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On Dec 7, 2007 9:45 AM, mandel <oh no.es> wrote:
 if(bar && Foo)

presumably you mean static if (bar && foo)
Dec 07 2007
prev sibling next sibling parent mandel <oh no.es> writes:
On Fri, 07 Dec 2007 10:40:01 +0000, Janice Caron wrote:

 On Dec 7, 2007 9:45 AM, mandel <oh no.es> wrote:
 if(bar && Foo)

presumably you mean static if (bar && foo)

right. :)
Dec 07 2007
prev sibling parent mandel <oh no.es> writes:
On Fri, 07 Dec 2007 02:47:36 -0800, Walter Bright wrote:
 The version statement is limited in that you cannot do !foo or
 foo&&bar||baz. Rather than a bug, that is deliberate. I've seen a lot of
 code that, over the years, accumulated detritus like:
 
      #if FOO || BAR>0x1234 && BAZ && !HACK
 
 These tend to snarl themselves into such a rat's nest of conditionals
 the only way to figure out which lines actually got compiled was to
 examine the preprocessor output. (Another consequence of these is that,
 inevitably, the various conditionals were WRONG as they were layered on
 by people who didn't really understand the code.)
 
 So, by limiting the version statement, the idea is to encourage the
 programmer to think in terms of distinct versions being generated, and
 then code in terms of those distinct versions - each of those versions
 having a name.

I'am aware of that problem and understand the design decision. Still, I can't get rid of the desire to give more power to the programmer by simplifying stuff. :> But I can code with the way it is.
Dec 07 2007
prev sibling next sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
mandel wrote:
 A proposal in a nutshell:
 
 - removal of the keywords "unittest, "version" and similar.
 
 - replaced by global compile time variables.
 
 - "dmd -<name>=<value>" to set them. Variables not found result in 
 compiler warnings
 
 - "dmd -list version*" or similar to list all global variable names with 
 prefix "version"
 
 -> less keywords, more powerfull control (use in boolean expressions), 
 more native syntax, easier to understand
 
 Ideas? Problems? Objections?

There are two things I like in the current system that will be lost with this proposal: 1. Distinction between conditional compilation as in different versions of the software and use of static if for meta- and generic programming 2. A standardized naming scheme. For example, there's nothing magical about the debug keyword as far as I know, it could just be replaced with version(Debug). But it's nice that everybody uses the same thing for the same purpose.
Dec 07 2007
parent Walter Bright <newshound1 digitalmars.com> writes:
Lutger wrote:
 For example, there's nothing magical 
 about the debug keyword as far as I know, it could just be replaced with 
 version(Debug). But it's nice that everybody uses the same thing for the 
 same purpose.

You're quite right in your assessment of the debug conditional. It stems from my experience (and that of some managers who begged me for this) that every C/C++ project has their own, unique, way of building for debug. It's not that any of them are wrong, it's just that they're all different. No standardized convention has ever emerged, yet all these debug schemes essentially do the same thing. Providing a standard means of debug compilation means: 1) Projects developed by different groups will naturally gravitate towards using it, rather than invent their own, aiding source code portability. 2) Programmers can move from project to project with one less coding convention they must relearn. 3) Standardized tools can be developed to manipulate the debug compilations. 4) A standardized scheme is something that can be enforced by larger organizations.
Dec 07 2007
prev sibling next sibling parent Christopher Wright <dhasenan gmail.com> writes:
mandel wrote:
 Ideas? Problems? Objections?
 
 ...might be hairy to implement?

Maybe. And it would be EXTREMELY hairy to read. ...what would happen if you compiled with '-if=false' ?
Dec 07 2007
prev sibling parent reply Robby <robby.lansaw gmail.com> writes:
mandel wrote:
 A proposal in a nutshell:
 
 - removal of the keywords "unittest, "version" and similar.
 
 - replaced by global compile time variables.
 
 - "dmd -<name>=<value>" to set them. Variables not found result in 
 compiler warnings
 
 - "dmd -list version*" or similar to list all global variable names with 
 prefix "version"
 
 -> less keywords, more powerfull control (use in boolean expressions), 
 more native syntax, easier to understand
 
 Ideas? Problems? Objections?
 
 btw.:
 bool enableXYZ;
 
 if(enableXFZ) import foo.Bar;
 
 ...might be hairy to implement?

Please please don't. From my standpoint, and converting over 70k lines of code over to D I can attest how easy the simplistic way of how D handles versions is so nice in the long run. I do like the idea of version (a,b,c) though, oddly enough. Now if I could get a way to enforce a type can't be null by the language itself, it would save a lot of if(whatever == null) cruft I have lined throughout from the *other* language port we're doing:(. yanno, something that says I expect class Whatever, I want class Whatever and don't you damn well give me null. I have noticed a push for changing adding complication for unittest as well, but I hope it stays quite similar, though I really would like a lil more fine tuning of how it's ran.
Dec 07 2007
parent Robby <robby.lansaw gmail.com> writes:
Robby wrote:
 mandel wrote:
 A proposal in a nutshell:

 - removal of the keywords "unittest, "version" and similar.

 - replaced by global compile time variables.

 - "dmd -<name>=<value>" to set them. Variables not found result in 
 compiler warnings

 - "dmd -list version*" or similar to list all global variable names 
 with prefix "version"

 -> less keywords, more powerfull control (use in boolean expressions), 
 more native syntax, easier to understand

 Ideas? Problems? Objections?

 btw.:
 bool enableXYZ;

 if(enableXFZ) import foo.Bar;

 ...might be hairy to implement?

Please please don't. From my standpoint, and converting over 70k lines of code over to D I can attest how easy the simplistic way of how D handles versions is so nice in the long run. I do like the idea of version (a,b,c) though, oddly enough. Now if I could get a way to enforce a type can't be null by the language itself, it would save a lot of if(whatever == null) cruft I have lined throughout from the *other* language port we're doing:(. yanno, something that says I expect class Whatever, I want class Whatever and don't you damn well give me null. I have noticed a push for changing adding complication for unittest as well, but I hope it stays quite similar, though I really would like a lil more fine tuning of how it's ran.

Dec 07 2007