www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Can I do an or in a version block?

reply "Tyler Jameson Little" <beatgammit gmail.com> writes:
I would like to do something like this:

version (linux || BSD) {
     // do something...
} else {
     version (Windows) {
         // do something else
     } else {
         // do something else
         assert(false, "Unsupported operating system");
     }
}

The only way I've been able to do this, is by splitting up the 
two versions and repeat code.

Is there a better way to do this? A static if can do this, so is 
there a way that I can use a static if somehow?
Mar 07 2012
next sibling parent reply James Miller <james aatch.net> writes:
On 8 March 2012 18:38, Tyler Jameson Little <beatgammit gmail.com> wrote:
 I would like to do something like this:

 version (linux || BSD) {
 =C2=A0 =C2=A0// do something...
 } else {
 =C2=A0 =C2=A0version (Windows) {
 =C2=A0 =C2=A0 =C2=A0 =C2=A0// do something else
 =C2=A0 =C2=A0} else {
 =C2=A0 =C2=A0 =C2=A0 =C2=A0// do something else
 =C2=A0 =C2=A0 =C2=A0 =C2=A0assert(false, "Unsupported operating system");
 =C2=A0 =C2=A0}
 }

 The only way I've been able to do this, is by splitting up the two versio=
ns
 and repeat code.

 Is there a better way to do this? A static if can do this, so is there a =
way
 that I can use a static if somehow?
I don't think there is an 'elseif' for versions, probably because you are normally checking mutually exclusive version descriptions. Otherwise, its probably a good idea to keep the syntax as is, since it stops people from abusing the mechanic. -- James Miller
Mar 07 2012
next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/07/2012 10:07 PM, James Miller wrote:
 On 8 March 2012 18:38, Tyler Jameson Little<beatgammit gmail.com>  wrote:
 I would like to do something like this:

 version (linux || BSD) {
     // do something...
 } else {
     version (Windows) {
         // do something else
     } else {
         // do something else
         assert(false, "Unsupported operating system");
     }
 }

 The only way I've been able to do this, is by splitting up the two versions
 and repeat code.

 Is there a better way to do this? A static if can do this, so is there a way
 that I can use a static if somehow?
I don't think there is an 'elseif' for versions, probably because you are normally checking mutually exclusive version descriptions. Otherwise, its probably a good idea to keep the syntax as is, since it stops people from abusing the mechanic. -- James Miller
I had played with this in the past. The assignment to version has an interesting meaning of "collecting" everything assigned to it: import std.stdio; version (linux) { version = linuxOrBSD; version = foo; } version (BSD) { version = linuxOrBSD; version = foo; } void main() { version (linuxOrBSD) { writeln("linux or BSD"); // do something... } else { version (Windows) { // do something else } else { // do something else assert(false, "Unsupported operating system"); } } // Later on even this works version (foo) { writeln("even foo!"); } } Ali
Mar 07 2012
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 08 Mar 2012 01:07:08 -0500, James Miller <james aatch.net> wrote:

 On 8 March 2012 18:38, Tyler Jameson Little <beatgammit gmail.com> wrote:
 I would like to do something like this:

 version (linux || BSD) {
    // do something...
 } else {
    version (Windows) {
        // do something else
    } else {
        // do something else
        assert(false, "Unsupported operating system");
    }
 }

 The only way I've been able to do this, is by splitting up the two  
 versions
 and repeat code.

 Is there a better way to do this? A static if can do this, so is there  
 a way
 that I can use a static if somehow?
I don't think there is an 'elseif' for versions, probably because you are normally checking mutually exclusive version descriptions. Otherwise, its probably a good idea to keep the syntax as is, since it stops people from abusing the mechanic.
Noting that there actually isn't an elseif keyword for if either, of course there is the same construct for version: // if if(cond1) {} else if(cond2) {} // version version(version1) {} else version(version2) {} -Steve
Mar 08 2012
parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I find it interesting that having this feature would somehow "enable"
abuse, yet we can do so much abuse already with CTFE, templates, and
string mixins. One large pain in the ass is to pass an integral at
compile time. I sometimes wish to use a syntax such as "version(foo ==
5) {}". The only alternative that I know of is to use string imports
via -J switch to initialize an enum. Compare that with the simple
-Dfoo=5 in DMC/GCC/etc. We might not have globals or macros in D, but
at least 'version(foo) = 5' or something similar should work. It's
also strange that version uses its own meaning of the equals operator,
I really dislike that.

Generally it seems version is the poorest-developed feature of D. And
the counterargument for new features is always a Go-like stance ("you
just won't need it"/"people will abuse the feature").

Of course all I can do now is whine and not propose something better.
:) But there have been a few threads about version and its issues. I
think it's only a matter of time before D gets popular enough that we
get these kinds of threads every other day. Maybe then something will
change.
Mar 08 2012
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, March 08, 2012 06:38:48 Tyler Jameson Little wrote:
 I would like to do something like this:
 
 version (linux || BSD) {
      // do something...
 } else {
      version (Windows) {
          // do something else
      } else {
          // do something else
          assert(false, "Unsupported operating system");
      }
 }
 
 The only way I've been able to do this, is by splitting up the
 two versions and repeat code.
 
 Is there a better way to do this? A static if can do this, so is
 there a way that I can use a static if somehow?
You can do version(x) {} else version(y) {} else {} but there is no logical and or logical or with versions. It's _only_ checking whether a particular version exists or not. Walter Bright is completely against having anything more complicated with versioning, since he thinks that it just engenders bad code and bugs. Now, you could do version(x) version = xOrY else version(y) version = xOrY version(xOrY) {} and then xOrY will exist for the rest of that module. But that's as close as you're going to ge to logical and or logical or for versions. Of course, if the issue is linux || FreeBSD, you might want to just consider using Posix. Unless you're doing something that is specific to linux and FreeBSD but not Posix in general (which I would expect to be unlikely), Posix will do the trick just fine. - Jonathan M Davis
Mar 07 2012
next sibling parent "Tyler Jameson Little" <beatgammit gmail.com> writes:
 Now, you could do

 version(x)
     version = xOrY
 else version(y)
     version = xOrY

 version(xOrY) {}
Huh, clever! I like it!! I hope I don't have to do that very often, though...
 Of course, if the issue is linux || FreeBSD, you might want to 
 just consider
 using Posix. Unless you're doing something that is specific to 
 linux and
 FreeBSD but not Posix in general (which I would expect to be 
 unlikely), Posix
 will do the trick just fine.
Yeah, that was just an example. Perhaps a better example would be comparing versions of something: version (LIBV1 || LIBV2) { // include some dirty hacks for old versions } else { // do some new fancy stuff for new features } I was mostly thinking that there are things that linux and BSD share that other BSDs may not. I know that Mac OS X has some subtle differences in a few things. Anyway, I think this answers my question. I can get by with using your suggestion for those (hopefully) rare cases where I need something more specific. Thanks!
Mar 07 2012
prev sibling next sibling parent "Tyler Jameson Little" <beatgammit gmail.com> writes:
 Now, you could do

 version(x)
     version = xOrY
 else version(y)
     version = xOrY

 version(xOrY) {}
Huh, clever! I like it!! I hope I don't have to do that very often, though...
 Of course, if the issue is linux || FreeBSD, you might want to 
 just consider
 using Posix. Unless you're doing something that is specific to 
 linux and
 FreeBSD but not Posix in general (which I would expect to be 
 unlikely), Posix
 will do the trick just fine.
Yeah, that was just an example. Perhaps a better example would be comparing versions of something: version (LIBV1 || LIBV2) { // include some dirty hacks for old versions } else { // do some new fancy stuff for new features } I was mostly thinking that there are things that linux and BSD share that other BSDs may not. I know that Mac OS X has some subtle differences in a few things. Anyway, I think this answers my question. I can get by with using your suggestion for those (hopefully) rare cases where I need something more specific. Thanks!
Mar 07 2012
prev sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Thu, 08 Mar 2012 06:12:44 -0000, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:
 On Thursday, March 08, 2012 06:38:48 Tyler Jameson Little wrote:
 I would like to do something like this:

 version (linux || BSD) {
      // do something...
 } else {
      version (Windows) {
          // do something else
      } else {
          // do something else
          assert(false, "Unsupported operating system");
      }
 }

 The only way I've been able to do this, is by splitting up the
 two versions and repeat code.

 Is there a better way to do this? A static if can do this, so is
 there a way that I can use a static if somehow?
 <snip>... Walter Bright is completely
 against having anything more complicated with versioning, since he  
 thinks that
 it just engenders bad code and bugs.
IIRC the argument was that we should define version identifiers for 'features' or 'behaviours' not for platforms, etc. So, given the 2nd example, instead of: version (LIBV1 || LIBV2) { // include some dirty hacks for old versions } else { // do some new fancy stuff for new features } do: version (LIBV1) version = LIB_OLD version (LIBV2) version = LIB_OLD version (LIB_OLD) { // dirty hacks } else { // new fancy stuff } Regan -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Mar 08 2012
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-03-08 06:38, Tyler Jameson Little wrote:
 I would like to do something like this:

 version (linux || BSD) {
 // do something...
 } else {
 version (Windows) {
 // do something else
 } else {
 // do something else
 assert(false, "Unsupported operating system");
 }
 }

 The only way I've been able to do this, is by splitting up the two
 versions and repeat code.

 Is there a better way to do this? A static if can do this, so is there a
 way that I can use a static if somehow?
A workaround is to use static if constants, here's a start: https://github.com/jacob-carlborg/mambo/blob/master/util/Version.d -- /Jacob Carlborg
Mar 08 2012
prev sibling parent reply Ary Manzana <ary esperanto.org.ar> writes:
On 3/8/12 2:38 AM, Tyler Jameson Little wrote:
 I would like to do something like this:

 version (linux || BSD) {
 // do something...
 } else {
 version (Windows) {
 // do something else
 } else {
 // do something else
 assert(false, "Unsupported operating system");
 }
 }

 The only way I've been able to do this, is by splitting up the two
 versions and repeat code.

 Is there a better way to do this? A static if can do this, so is there a
 way that I can use a static if somehow?
I don't think it would be hard to implement boolean logic inside version. Would it make sense if I make a pull request for it? (because every now and then somebody stumbles upon this issue, and it looks like it could be implemented really easily)
Mar 08 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 08, 2012 at 05:56:09PM -0300, Ary Manzana wrote:
[...]
 I don't think it would be hard to implement boolean logic inside
 version.
It's not hard at all.
 Would it make sense if I make a pull request for it?
Walter would reject it. He has stated clearly in the past that he intended version to be simple and minimal, and that adding anything onto it will only result in abuses. T -- Why ask rhetorical questions? -- JC
Mar 08 2012
parent reply Ary Manzana <ary esperanto.org.ar> writes:
On 3/8/12 6:11 PM, H. S. Teoh wrote:
 On Thu, Mar 08, 2012 at 05:56:09PM -0300, Ary Manzana wrote:
 [...]
 I don't think it would be hard to implement boolean logic inside
 version.
It's not hard at all.
 Would it make sense if I make a pull request for it?
Walter would reject it. He has stated clearly in the past that he intended version to be simple and minimal, and that adding anything onto it will only result in abuses.
What kind of abuses? I don't understand that logic in a language that allows you to use pointers, alloc memory however you want, and get segfaults for null memory access.
Mar 08 2012
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 08, 2012 at 10:25:53PM -0300, Ary Manzana wrote:
 On 3/8/12 6:11 PM, H. S. Teoh wrote:
On Thu, Mar 08, 2012 at 05:56:09PM -0300, Ary Manzana wrote:
[...]
I don't think it would be hard to implement boolean logic inside
version.
It's not hard at all.
Would it make sense if I make a pull request for it?
Walter would reject it. He has stated clearly in the past that he intended version to be simple and minimal, and that adding anything onto it will only result in abuses.
What kind of abuses? I don't understand that logic in a language that allows you to use pointers, alloc memory however you want, and get segfaults for null memory access.
Ask Walter. It was his opinion. T -- People walk. Computers run.
Mar 08 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/09/2012 02:25 AM, Ary Manzana wrote:
 On 3/8/12 6:11 PM, H. S. Teoh wrote:
 On Thu, Mar 08, 2012 at 05:56:09PM -0300, Ary Manzana wrote:
 [...]
 I don't think it would be hard to implement boolean logic inside
 version.
It's not hard at all.
 Would it make sense if I make a pull request for it?
Walter would reject it. He has stated clearly in the past that he intended version to be simple and minimal, and that adding anything onto it will only result in abuses.
What kind of abuses?
Just have a look at reasonably portable C libraries that use the C preprocessor for versioning. IIRC Walter pointed to the Hans-Boehm GC the last time this issue was brought up.
 I don't understand that logic in a language that
 allows you to use pointers, alloc memory however you want, and get
 segfaults for null memory access.
Sorry, but this does not make any sense.
Mar 09 2012
parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I have a felling people will end up abusing string mixins to generate
version statements, and this will be the exact opposite effect Walter
wanted. The same story goes for unittests which can't be independently
ran to get a list of all failing unittests, and so people are coming
up with their own custom unittest framework (e.g. the Orange library).
Mar 09 2012
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/09/2012 06:20 AM, Andrej Mitrovic wrote:

 The same story goes for unittests which can't be independently
 ran to get a list of all failing unittests
D unittest blocks are for code correctness (as opposed to other meanings of the unfortunately overused term "unit testing" e.g. the functional testing of the end product). From that point of view, there should not be even a single test failing.
, and so people are coming
 up with their own custom unittest framework (e.g. the Orange library).
Yes, some unit test features are missing. From my day-to-day use I would like to have the following: - Ensure that a specific exception is thrown - Test fixtures That obviously reflects my use of unit tests but I really don't care how many tests are failing. The reason is, I start with zero failures and I finish with zero failures. Any code that breaks an existing test is either buggy or exposes an issue with the test, which must be dealt with right then. Ali
Mar 13 2012
parent reply Ary Manzana <ary esperanto.org.ar> writes:
On 3/13/12 2:21 PM, Ali Çehreli wrote:
 On 03/09/2012 06:20 AM, Andrej Mitrovic wrote:

  > The same story goes for unittests which can't be independently
  > ran to get a list of all failing unittests

 D unittest blocks are for code correctness (as opposed to other meanings
 of the unfortunately overused term "unit testing" e.g. the functional
 testing of the end product). From that point of view, there should not
 be even a single test failing.

  >, and so people are coming
  > up with their own custom unittest framework (e.g. the Orange library).

 Yes, some unit test features are missing. From my day-to-day use I would
 like to have the following:

 - Ensure that a specific exception is thrown

 - Test fixtures

 That obviously reflects my use of unit tests but I really don't care how
 many tests are failing. The reason is, I start with zero failures and I
 finish with zero failures. Any code that breaks an existing test is
 either buggy or exposes an issue with the test, which must be dealt with
 right then.

 Ali
How can you re-run just a failing test? (without having to run all the previous tests that will succeed?)
Mar 13 2012
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/13/2012 11:04 AM, Ary Manzana wrote:
 On 3/13/12 2:21 PM, Ali Çehreli wrote:
 On 03/09/2012 06:20 AM, Andrej Mitrovic wrote:

 The same story goes for unittests which can't be independently
 ran to get a list of all failing unittests
D unittest blocks are for code correctness (as opposed to other meanings of the unfortunately overused term "unit testing" e.g. the functional testing of the end product). From that point of view, there should not be even a single test failing.
, and so people are coming
 up with their own custom unittest framework (e.g. the Orange library).
Yes, some unit test features are missing. From my day-to-day use I would like to have the following: - Ensure that a specific exception is thrown - Test fixtures That obviously reflects my use of unit tests but I really don't care how many tests are failing. The reason is, I start with zero failures and I finish with zero failures. Any code that breaks an existing test is either buggy or exposes an issue with the test, which must be dealt with right then. Ali
How can you re-run just a failing test? (without having to run all the previous tests that will succeed?)
I know that there are test suites too and Unittest++, the framework that we use, supports them but we don't use suites. There has never been a need to run a subset of the tests for us. The tests almost by definition must run very fast anyway. We don't even notice that they get run automatically as a part of the build process. We are getting a little off topic here but I've been following the recent unit test thread about writing to files. Unit tests should not have external interactions like that either. For example, no test should connect to an actual server to do some interaction. Developers wouldn't want that to happen every time a .d file is compiled. :) (Solutions like mocks, fakes, stubs, etc. do exist. And yes, I know that they are sometimes non-trivial.) Ali
Mar 13 2012
next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 3/13/12, Ali =C7ehreli <acehreli yahoo.com> wrote:
 Developers wouldn't
 want that to happen every time a .d file is compiled.
Well luckily unittests don't run when you compile a .d file but when you run the app! :)
Mar 13 2012
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/13/2012 11:49 AM, Andrej Mitrovic wrote:
 On 3/13/12, Ali Çehreli<acehreli yahoo.com>  wrote:
 Developers wouldn't
 want that to happen every time a .d file is compiled.
Well luckily unittests don't run when you compile a .d file but when you run the app! :)
Good point. :) Our C++ unit tests are a part of a test binary that has a make file dependency on the library that the .cc files contribute to. A changed .cc causes its .o to be built, the .o causes its .a to be built, the .a causes its unit test application to be built, and finally the unit test application is executed as a part of the library's post build step. Ali
Mar 13 2012
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Mar 13, 2012 at 11:28:24AM -0700, Ali Çehreli wrote:
[...]
 We are getting a little off topic here but I've been following the
 recent unit test thread about writing to files. Unit tests should not
 have external interactions like that either. For example, no test
 should connect to an actual server to do some interaction.  Developers
 wouldn't want that to happen every time a .d file is compiled. :)
 (Solutions like mocks, fakes, stubs, etc. do exist. And yes, I know
 that they are sometimes non-trivial.)
[...] It's not about whether unittests should write to files, but about testing a part of the code that operates on files. So you create some test data in the unittest and put it in the file, then pass the file to the function being tested. Ideally, this should be done in some kind of tmpfs, which is only accessible to the program, and which is discarded by the OS once the testing is finished. You still have the case of non-trivial test data, though. Sometimes there's a large dataset with a known result that you want to use in a unittest, to ensure that your latest changes didn't break a known non-trivial working case. I suppose you could argue that these kinds of tests belong in an external test framework, but that's the kind of thing that discourages people from actually writing test cases in the first place. I know I'll be too lazy to do this if it wasn't as simple as adding a unittest block to my code. It's just too much trouble to implement an external framework, write the test case in a separate file, update the build system to include it in the test suite, only to have to scrap a lot of this effort later when you suddenly realize that there's a better algorithm you can use which invalidates most of the original test case. Whereas if this was just an embedded unittest block, you can delete or comment out the block, replace it with a new test relevant to the new code, and keep going. Seems like a small difference, but having to edit 2-3 different files just to update a test case as opposed to continuing to work with the same source file you've been working on can make the difference between the programmer deciding to put it off till later (which usually means it doesn't get done) vs. doing it immediately without too much interruption (test cases are up-to-date and more thorough). T -- I'm still trying to find a pun for "punishment"...
Mar 13 2012
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, March 13, 2012 15:04:09 Ary Manzana wrote:
 How can you re-run just a failing test? (without having to run all the
 previous tests that will succeed?)
You can't, not without essentially creating your own unit testing framework. D's unit testing framework is quite simple. If you compile with -unittest, then the unittest blocks are all run before main is run. If any unittest block in a module fails, then no further unittest blocks in that module are run (though unittest blocks in other modules are run). If any unittest block failed, then main is never run, otherwise the program continues normally. There is no way to rerun specific unit tests or have any control whatsoever which unit tests run unless you create separate programs which only compile in specific modules so that only the unit tests in those modules are run. And even then, you have no control over _which_ tests in a unittest block run unless you play with version statements or whatnot. D's unit testing framework works quite well as long as you're willing to always run all of the tests. If you want more control than that, you have to play games if not outright create your own unit testing framework. - Jonathan M Davis
Mar 13 2012