www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - OR in version conditional compilation

reply IGotD- <nise nise.com> writes:
I have not seen any example where version has several OR matches.

Example idiom:

version(X86_64 || X86)
{

}
else version(ARM || Thumb)
{

}...

you get the idea. So is this possible at all or do you have to 
duplicate the code for each version identifier despite they are 
equal for many version identifiers?
Mar 18 2020
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 3/18/20 12:23 PM, IGotD- wrote:
 I have not seen any example where version has several OR matches.
 
 Example idiom:
 
 version(X86_64 || X86)
 {
 
 }
 else version(ARM || Thumb)
 {
 
 }...
 
 you get the idea. So is this possible at all or do you have to duplicate 
 the code for each version identifier despite they are equal for many 
 version identifiers?
No, it's not possible. And it won't ever be possible, Walter is dead-set against it. If you want to know the history, look waaaay back in the forums. This question comes up every so often. There is a workaround though: template v(string versionID) { mixin("version(" ~ versionID ~ ") enum v = true; else enum v = false;"); } static if(v!"X86_64" || v!"X86") ... -Steve
Mar 18 2020
prev sibling next sibling parent MoonlightSentinel <moonlightsentinel disroot.org> writes:
On Wednesday, 18 March 2020 at 16:23:26 UTC, IGotD- wrote:
 you get the idea. So is this possible at all or do you have to 
 duplicate the code for each version identifier despite they are 
 equal for many version identifiers?
The usual workaround is to define a common version, e.g. version(X86) version = X86_ANY version(X86_64) version = X86_ANY version(X86_ANY) { // your code here }
Mar 18 2020
prev sibling next sibling parent Kagamin <spam here.lot> writes:
https://issues.dlang.org/show_bug.cgi?id=19495#c1
Mar 18 2020
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, March 18, 2020 10:23:26 AM MDT IGotD- via Digitalmars-d-learn 
wrote:
 I have not seen any example where version has several OR matches.

 Example idiom:

 version(X86_64 || X86)
 {

 }
 else version(ARM || Thumb)
 {

 }...

 you get the idea. So is this possible at all or do you have to
 duplicate the code for each version identifier despite they are
 equal for many version identifiers?
To add to what the others have said, the reasons that Walter is against having boolean conditions in version statements have to do with how using boolean conditions in #ifdefs in C/C++ has historically been a big source of bugs. So, disallowing it helps prevent certain classes of bugs. It's why druntime duplicates most C declarations across platforms. In general, I think that Walter's approach here is probably the right one, but it can certainly be annoying in cases where you have to duplicate code that actually is the same rather than being subtly different, and a lot of people dislike it enough that they use workarounds like those discussed in this thread. And of course, some of the same bugs that come up with #ifdefs come up with static ifs in generic code (particularly with range-based code that changes what it's doing based on arange's type), but at least those can be found with thorough tests on a single platform, whereas version-related bugs tend to require that you run thorough tests on each platform. - Jonathan M Davis
Mar 20 2020
parent reply jxel <jxel gmall.com> writes:
On Friday, 20 March 2020 at 21:03:55 UTC, Jonathan M Davis wrote:
 On Wednesday, March 18, 2020 10:23:26 AM MDT IGotD- via 
 Digitalmars-d-learn wrote:
 I have not seen any example where version has several OR 
 matches.

 Example idiom:

 version(X86_64 || X86)
 {

 }
 else version(ARM || Thumb)
 {

 }...

 you get the idea. So is this possible at all or do you have to 
 duplicate the code for each version identifier despite they 
 are equal for many version identifiers?
To add to what the others have said, the reasons that Walter is against having boolean conditions in version statements have to do with how using boolean conditions in #ifdefs in C/C++ has historically been a big source of bugs. So, disallowing it helps prevent certain classes of bugs. It's why druntime duplicates most C declarations across platforms.
What kind of bugs are those?
 In general, I think that Walter's approach here is probably the 
 right one, but it can certainly be annoying in cases where you 
 have to duplicate code that actually is the same rather than 
 being subtly different, and a lot of people dislike it enough 
 that they use workarounds like those discussed in this thread.
Sadly it still shares probably the worst bug with the C preposser in that anything that isnt defined simply evaluates to false. If you have a typo then the code will still "work". His approach only works if you can put an assert in the else branch. Which is the case for C/C++ as well. That isnt always possible, as a result you still have the same problem with typos.
 And of course, some of the same bugs that come up with #ifdefs 
 come up with static ifs in generic code (particularly with 
 range-based code that changes what it's doing based on arange's 
 type), but at least those can be found with thorough tests on a 
 single platform, whereas version-related bugs tend to require 
 that you run thorough tests on each platform.

 - Jonathan M Davis
You still need to test your code on those platforms, so if you are supporting them you still have related problems.
Mar 20 2020
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, March 20, 2020 4:33:58 PM MDT jxel via Digitalmars-d-learn wrote:
 On Friday, 20 March 2020 at 21:03:55 UTC, Jonathan M Davis wrote:
 On Wednesday, March 18, 2020 10:23:26 AM MDT IGotD- via

 Digitalmars-d-learn wrote:
 I have not seen any example where version has several OR
 matches.

 Example idiom:

 version(X86_64 || X86)
 {

 }
 else version(ARM || Thumb)
 {

 }...

 you get the idea. So is this possible at all or do you have to
 duplicate the code for each version identifier despite they
 are equal for many version identifiers?
To add to what the others have said, the reasons that Walter is against having boolean conditions in version statements have to do with how using boolean conditions in #ifdefs in C/C++ has historically been a big source of bugs. So, disallowing it helps prevent certain classes of bugs. It's why druntime duplicates most C declarations across platforms.
What kind of bugs are those?
There are a variety of issues that come from it, and it's been discussed at length in past threads (and much better than I'll explain here, I'm sure), but the main issues stem from the fact that when you're writing code that is platform-dependent but using it on multiple platforms, it can become really easy to break stuff as the code is altered over time. e.g. you can make a change that works perfectly fine on the platform that you're developing on without realizing that it won't work on the other platforms sharing the same #ifdef block, and while you should be testing such code on all supported platforms, it often doesn't happen, and even when it does happen, it's usually much further down the line after many more changes have been made. It would be highly abnormal for someone to test what they're working on on all of the relevant platforms as they're working on it. It also can get really tricky to avoid subtle bugs once you start having more complex boolean expressions and/or have nested #ifdefs. That's where things tend to get _really_ bad. Another big problem comes in when you just assume that the code from one platform will work with another and alter existing #ifdefs to be used on the new platform. Suddenly code that was only supposed to be used on one platform is being used on multiple, and it can cause big problems depending on what that code actualy does and what assumptions were made when writing it. By simply following the basic idiom of version(A) { } else version(B) { } else static assert(false, "Platform not supported"); you avoid problems that stem from code being used an a platform that it's not intended for, and you get compilation errors if you try to use code on a platform that it wasn't made to work on yet. It can result in more code duplication than many people like, but it's ultimately less error-prone. Either way, in general, it's far better to design your code such that as little of it as possible is platform-dependent and that those parts that are are well-encapsulated. - Jonathan M Davis
Mar 20 2020
parent jxel <jxel gmall.com> writes:
On Saturday, 21 March 2020 at 00:12:20 UTC, Jonathan M Davis 
wrote:
 On Friday, March 20, 2020 4:33:58 PM MDT jxel via 
 Digitalmars-d-learn wrote:
 On Friday, 20 March 2020 at 21:03:55 UTC, Jonathan M Davis 
 wrote:
 On Wednesday, March 18, 2020 10:23:26 AM MDT IGotD- via

 Digitalmars-d-learn wrote:
 I have not seen any example where version has several OR 
 matches.

 Example idiom:

 version(X86_64 || X86)
 {

 }
 else version(ARM || Thumb)
 {

 }...

 you get the idea. So is this possible at all or do you have 
 to duplicate the code for each version identifier despite 
 they are equal for many version identifiers?
To add to what the others have said, the reasons that Walter is against having boolean conditions in version statements have to do with how using boolean conditions in #ifdefs in C/C++ has historically been a big source of bugs. So, disallowing it helps prevent certain classes of bugs. It's why druntime duplicates most C declarations across platforms.
What kind of bugs are those?
There are a variety of issues that come from it, and it's been discussed at length in past threads (and much better than I'll explain here, I'm sure), but the main issues stem from the fact that when you're writing code that is platform-dependent but using it on multiple platforms, it can become really easy to break stuff as the code is altered over time. e.g. you can make a change that works perfectly fine on the platform that you're developing on without realizing that it won't work on the other platforms sharing the same #ifdef block, and while you should be testing such code on all supported platforms, it often doesn't happen, and even when it does happen, it's usually much further down the line after many more changes have been made. It would be highly abnormal for someone to test what they're working on on all of the relevant platforms as they're working on it.
None of that is limited specifically to ifdefs. If you modify code not in an ifdef you can still cause bugs that only materialize on specific platforms. This is the nature of building for multiple platforms at the low level, hell you'll still have problems even in Java. The D test suite doesn't run unit tests for every platform for all libraries. There's also debug assert statements that fail, and at least last I checked for some platforms didn't run debug builds, so the tests don't catch this. And not everyone develops for those platforms so I guess no one does a debug build on their systems either.
 It also can get really tricky to avoid subtle bugs once you 
 start having more complex boolean expressions and/or have 
 nested #ifdefs. That's where things tend to get _really_ bad. 
 Another big problem comes in when you just assume that the code 
 from one platform will work with another and alter existing 
 #ifdefs to be used on the new platform. Suddenly code that was 
 only supposed to be used on one platform is being used on 
 multiple, and it can cause big problems depending on what that 
 code actualy does and what assumptions were made when writing 
 it. By simply following the basic idiom of

 version(A)
 {
 }
 else version(B)
 {
 }
 else
     static assert(false, "Platform not supported");

 you avoid problems that stem from code being used an a platform 
 that it's not intended for, and you get compilation errors if 
 you try to use code on a platform that it wasn't made to work 
 on yet. It can result in more code duplication than many people 
 like, but it's ultimately less error-prone. Either way, in 
 general, it's far better to design your code such that as 
 little of it as possible is platform-dependent and that those 
 parts that are are well-encapsulated.

 - Jonathan M Davis
Like I said in my other comment. This only works if you can assert out of it, and in C and C++ it is the same. There's a bigger problem that still isnt solved, if you need one version statement that doesn't assert to failure. Since a typo will just evaluate to false, the version statement may never be active under any circumstance and it would be difficult to fins such a bug. For example for conguration options, there's no other versions you would put in else versions, and it isnt intended to fail if that configuration version isnt there. The version feature inherited one of C's worst characteristics of the preprocessor for ifdef.
Mar 20 2020