digitalmars.D - Version block "conditions" with logical operators
- Tomer Filiba (21/21) May 10 2016 Hey guys,
- Joakim (18/39) May 10 2016 This has been discussed multiple times in the forum, Walter is
- Tomer Filiba (12/20) May 10 2016 ...
- Tomer Filiba (16/18) May 10 2016 Well, I've come up with
- Andrei Alexandrescu (2/19) May 10 2016 Not if we put it in the standard library :o). -- Andrei
- Artur Skawina via Digitalmars-d (22/42) May 11 2016 It is a hack; the main problem being that the check happens at
- Johan Engelen (3/7) May 10 2016 We resort to enums whenever 'version' is not adequate like this:
- Tomer Filiba (5/7) May 10 2016 A good example -- which only proves how the current version()
- Joakim (6/14) May 11 2016 That example is misleading, as that was translated from C++ and
- Walter Bright (2/7) May 11 2016 Please do. That code is an abomination.
- Joakim (6/17) May 13 2016 I'm trying, but Daniel seems against it, care to chip in?
- Walter Bright (2/6) May 13 2016 I know there's some controversy in that thread, I guess I need to check ...
- Nick Treleaven (5/8) May 10 2016 This is actually longer for 2 arguments, but can scale better:
- bitwise (18/39) May 11 2016 Still holding out hope Walter will change his mind here..
- Walter Bright (5/8) May 11 2016 Really? There are a few lines of that left in dmd, but as a result of me...
- John Colvin (6/8) May 11 2016 I'm convinced that you're argument is reasonable if version is
- Walter Bright (8/12) May 11 2016 Yes, I do.
- Andrew Pennebaker (6/54) Dec 13 2018 Most things aside from straight up
- Jonathan M Davis (5/32) Dec 13 2018 You might want to pay attention to the date of the post that you're repl...
Hey guys, Looking at our code base (weka), I realized it would be really useful if we had logical operators (negation, conjunction, disjunction) in the version's "condition" clause. Here's what I have in mind: version(!extra_checks) { ... } version(dlang_ver_2069 || dlang_ver_2070) { ... } Today we have lots of ugly code like version(unittest) {} else { ... } and bad-old copy-paste for the logical-or case I mentioned. Is there any reason for that versions can't take compound logical conditions? Alternatively, an isVersion(x) predicate that I could use in a static if could do the trick -- although I think ``version(x || y)`` is more readable than ``static if (isVersion(x) || isVersion(y))`` I think it could be a useful feature. Any thoughts? -tomer
May 10 2016
On Tuesday, 10 May 2016 at 11:12:58 UTC, Tomer Filiba wrote:Hey guys, Looking at our code base (weka), I realized it would be really useful if we had logical operators (negation, conjunction, disjunction) in the version's "condition" clause. Here's what I have in mind: version(!extra_checks) { ... } version(dlang_ver_2069 || dlang_ver_2070) { ... } Today we have lots of ugly code like version(unittest) {} else { ... } and bad-old copy-paste for the logical-or case I mentioned. Is there any reason for that versions can't take compound logical conditions? Alternatively, an isVersion(x) predicate that I could use in a static if could do the trick -- although I think ``version(x || y)`` is more readable than ``static if (isVersion(x) || isVersion(y))`` I think it could be a useful feature. Any thoughts? -tomerThis has been discussed multiple times in the forum, Walter is against it and I agree with him: http://forum.dlang.org/thread/op.xz6shob04sdys0 nicolass-macbook-pro.local http://forum.dlang.org/thread/n0u5v3$1lsh$1 digitalmars.com Static if can do this now using enums that you define by using those version conditions, but Walter advises against it. Another alternative is to put all such OS versioning logic in a build script somewhere and then version on features in your D code, which is probably cleanest, ie have a build script check if you're building for an OS that supports LIBRARY_X, then pass -version=LIBRARY_X to your build and version your D code using version(LIBRARY_X). If you use reggae (https://github.com/atilaneves/reggae), the logic that checks if you're using LIBRARY_X could be written in D too. The idea is to avoid having a bunch of such repeated conditional logic for versioning spread throughout the codebase, because it will be very error-prone and brittle.
May 10 2016
On Tuesday, 10 May 2016 at 11:48:12 UTC, Joakim wrote:This has been discussed multiple times in the forum, Walter is against it and I agree with him:Thanks for the pointersAnother alternative is to put all such OS versioning logic in a build script somewhere and then version on features in your D code, which is probably cleanest, ie have a build script check...The idea is to avoid having a bunch of such repeated conditional logic for versioning spread throughout the codebase, because it will be very error-prone and brittle.It's compiler-version-dependent, or version(unittest) or version(assert) or version(do_extra_checks). Which means my checks are inherently spread around the code. I counted 53 instances of "version.*else" in our code, which all look like version (XXX) {} else {...} I'm going to use my isVersion hack to avoid code duplication in "or", but for the rest of the code, I really think a version(!unittest) {...} is cleaner. -tomer
May 10 2016
On Tuesday, 10 May 2016 at 11:12:58 UTC, Tomer Filiba wrote:Alternatively, an isVersion(x) predicate that I could use in a static if could do the trickWell, I've come up with template isVersion(string ver) { mixin(format(q{ version(%s) { enum isVersion = true; } else { enum isVersion = false; } }, ver)); } pragma(msg, isVersion!"foo"); // false pragma(msg, isVersion!"assert"); // true But it feels hackish too -tomer
May 10 2016
On 5/10/16 2:48 PM, Tomer Filiba wrote:On Tuesday, 10 May 2016 at 11:12:58 UTC, Tomer Filiba wrote:Not if we put it in the standard library :o). -- AndreiAlternatively, an isVersion(x) predicate that I could use in a static if could do the trickWell, I've come up with template isVersion(string ver) { mixin(format(q{ version(%s) { enum isVersion = true; } else { enum isVersion = false; } }, ver)); } pragma(msg, isVersion!"foo"); // false pragma(msg, isVersion!"assert"); // true But it feels hackish too
May 10 2016
On 05/10/16 13:48, Tomer Filiba via Digitalmars-d wrote:On Tuesday, 10 May 2016 at 11:12:58 UTC, Tomer Filiba wrote:It is a hack; the main problem being that the check happens at the `isVersion` definition, and not where it's used. But, if you only care about "global" identifiers, you can just use something like this: ----------------------------------------------------- module mver; struct ver { template opDispatch(string M) { mixin(` version(`~M~`) enum opDispatch = true; else enum opDispatch = false; `); } } ----------------------------------------------------- import mver; static if (ver.linux && !ver.D_LP64) { /* ... */ } ----------------------------------------------------- arturAlternatively, an isVersion(x) predicate that I could use in a static if could do the trickWell, I've come up with template isVersion(string ver) { mixin(format(q{ version(%s) { enum isVersion = true; } else { enum isVersion = false; } }, ver)); } pragma(msg, isVersion!"foo"); // false pragma(msg, isVersion!"assert"); // true But it feels hackish too
May 11 2016
On Tuesday, 10 May 2016 at 11:12:58 UTC, Tomer Filiba wrote:Hey guys, Looking at our code base (weka), I realized it would be really useful if we had logical operators (negation, conjunction, disjunction) in the version's "condition" clause.We resort to enums whenever 'version' is not adequate like this: https://github.com/ldc-developers/ldc/blob/master/ddmd/globals.d#L18-L45
May 10 2016
On Tuesday, 10 May 2016 at 12:27:19 UTC, Johan Engelen wrote:We resort to enums whenever 'version' is not adequate like this: https://github.com/ldc-developers/ldc/blob/master/ddmd/globals.d#L18-L45A good example -- which only proves how the current version() block is insufficient. So instead of version(xxx), which states your intent clearly, you get lots of non-idiomatic static ifs, which are more cumbersome and error prone.
May 10 2016
On Tuesday, 10 May 2016 at 14:47:05 UTC, Tomer Filiba wrote:On Tuesday, 10 May 2016 at 12:27:19 UTC, Johan Engelen wrote:That example is misleading, as that was translated from C++ and the host half of it was removed a couple months ago: https://github.com/dlang/dmd/pull/5549/files I'll submit a PR for the rest: I'm sick of this argument that "ddmd is using static if, so why shouldn't I?"We resort to enums whenever 'version' is not adequate like this: https://github.com/ldc-developers/ldc/blob/master/ddmd/globals.d#L18-L45A good example -- which only proves how the current version() block is insufficient. So instead of version(xxx), which states your intent clearly, you get lots of non-idiomatic static ifs, which are more cumbersome and error prone.
May 11 2016
On 5/11/2016 6:52 PM, Joakim wrote:That example is misleading, as that was translated from C++ and the host half of it was removed a couple months ago: https://github.com/dlang/dmd/pull/5549/files I'll submit a PR for the rest: I'm sick of this argument that "ddmd is using static if, so why shouldn't I?"Please do. That code is an abomination.
May 11 2016
On Thursday, 12 May 2016 at 01:58:33 UTC, Walter Bright wrote:On 5/11/2016 6:52 PM, Joakim wrote:I'm trying, but Daniel seems against it, care to chip in? https://github.com/dlang/dmd/pull/5772 Specifically, do you want the changes in that PR? If so, do you prefer the use of TARGET_POSIX as a runtime variable or listing each TARGET_OS separately?That example is misleading, as that was translated from C++ and the host half of it was removed a couple months ago: https://github.com/dlang/dmd/pull/5549/files I'll submit a PR for the rest: I'm sick of this argument that "ddmd is using static if, so why shouldn't I?"Please do. That code is an abomination.
May 13 2016
On 5/13/2016 1:57 AM, Joakim wrote:I'm trying, but Daniel seems against it, care to chip in? https://github.com/dlang/dmd/pull/5772 Specifically, do you want the changes in that PR? If so, do you prefer the use of TARGET_POSIX as a runtime variable or listing each TARGET_OS separately?I know there's some controversy in that thread, I guess I need to check in.
May 13 2016
On 10/05/2016 12:12, Tomer Filiba wrote:Alternatively, an isVersion(x) predicate that I could use in a static if could do the trick -- although I think ``version(x || y)`` is more readable than ``static if (isVersion(x) || isVersion(y))``This is actually longer for 2 arguments, but can scale better: import std.meta : anySatisfy; static if (anySatisfy!(isVersion, "assert", "unittest")) ... (There's allSatisfy for x && y).
May 10 2016
On Tuesday, 10 May 2016 at 11:12:58 UTC, Tomer Filiba wrote:Hey guys, Looking at our code base (weka), I realized it would be really useful if we had logical operators (negation, conjunction, disjunction) in the version's "condition" clause. Here's what I have in mind: version(!extra_checks) { ... } version(dlang_ver_2069 || dlang_ver_2070) { ... } Today we have lots of ugly code like version(unittest) {} else { ... } and bad-old copy-paste for the logical-or case I mentioned. Is there any reason for that versions can't take compound logical conditions? Alternatively, an isVersion(x) predicate that I could use in a static if could do the trick -- although I think ``version(x || y)`` is more readable than ``static if (isVersion(x) || isVersion(y))`` I think it could be a useful feature. Any thoughts? -tomerStill holding out hope Walter will change his mind here.. His rationale is based on keeping code clean and organized, but given that D has no preprocessor macros, it will never look as bad as C++ code, or even close. Compounding versions in C++ accounts for a very small portion of the mess. When you have an #if VERS every 5 lines, however, you've got a problem...but then, you can do that with D's version just the same. The real solution is to properly encapsulate system-dependant code so that whatever version statement you need, is all in one place. Also when you have to hack 10 different macros together to invent a feature your language doesn't have, you've got a problem, but this is much less of a concern in D than C++. When even D gurus writing D compilers have to hack solutions together with static if to get by, its time to re-evaluate the situation. Bit
May 11 2016
On 5/11/2016 10:02 AM, bitwise wrote:When even D gurus writing D compilers have to hack solutions together with static if to get by,Really? There are a few lines of that left in dmd, but as a result of mechanical conversion from C++. There's other C++ cruft in there, too.its time to re-evaluate the situation.Actually, dmd is a nice example of how unnecessary it is. The dmd C++ source code used to be full of it.
May 11 2016
On Wednesday, 11 May 2016 at 20:37:35 UTC, Walter Bright wrote:Actually, dmd is a nice example of how unnecessary it is. The dmd C++ source code used to be full of it.I'm convinced that you're argument is reasonable if version is only for things like platforms, but it's used for a lot of other stuff e.g. version(PrintSomeExtraInfo) or version(CacheSomeStuffForPerformance). Do you think the same principle applies there?
May 11 2016
On 5/11/2016 1:42 PM, John Colvin wrote:I'm convinced that you're argument is reasonable if version is only for things like platforms, but it's used for a lot of other stuff e.g. version(PrintSomeExtraInfo) or version(CacheSomeStuffForPerformance). Do you think the same principle applies there?Yes, I do. https://github.com/dlang/dmd/pull/5767 I've also seen very good programmers find 'absolutely must have' uses for static if, used them, and caused bugs due to the tangled up nature of it. I had to go in and fix it. It takes a while to change one's thinking from the C++ #if expressions, but the result is worth it.
May 11 2016
On Wednesday, 11 May 2016 at 17:02:36 UTC, bitwise wrote:On Tuesday, 10 May 2016 at 11:12:58 UTC, Tomer Filiba wrote:Most things aside from straight up version([!]condition [op condition... [op condition...]) { ... } [else { ... }] are going to lead to surprising behavior, bad code, and gnashing of teeth. We shouldn't have to resort to macros to do this.Hey guys, Looking at our code base (weka), I realized it would be really useful if we had logical operators (negation, conjunction, disjunction) in the version's "condition" clause. Here's what I have in mind: version(!extra_checks) { ... } version(dlang_ver_2069 || dlang_ver_2070) { ... } Today we have lots of ugly code like version(unittest) {} else { ... } and bad-old copy-paste for the logical-or case I mentioned. Is there any reason for that versions can't take compound logical conditions? Alternatively, an isVersion(x) predicate that I could use in a static if could do the trick -- although I think ``version(x || y)`` is more readable than ``static if (isVersion(x) || isVersion(y))`` I think it could be a useful feature. Any thoughts? -tomerStill holding out hope Walter will change his mind here.. His rationale is based on keeping code clean and organized, but given that D has no preprocessor macros, it will never look as bad as C++ code, or even close. Compounding versions in C++ accounts for a very small portion of the mess. When you have an #if VERS every 5 lines, however, you've got a problem...but then, you can do that with D's version just the same. The real solution is to properly encapsulate system-dependant code so that whatever version statement you need, is all in one place. Also when you have to hack 10 different macros together to invent a feature your language doesn't have, you've got a problem, but this is much less of a concern in D than C++. When even D gurus writing D compilers have to hack solutions together with static if to get by, its time to re-evaluate the situation. Bit
Dec 13 2018
On Thursday, December 13, 2018 5:45:10 PM MST Andrew Pennebaker via Digitalmars-d wrote:On Wednesday, 11 May 2016 at 17:02:36 UTC, bitwise wrote:You might want to pay attention to the date of the post that you're replying to. It's about two-and-a-half years old. - Jonathan M DavisStill holding out hope Walter will change his mind here.. His rationale is based on keeping code clean and organized, but given that D has no preprocessor macros, it will never look as bad as C++ code, or even close. Compounding versions in C++ accounts for a very small portion of the mess. When you have an #if VERS every 5 lines, however, you've got a problem...but then, you can do that with D's version just the same. The real solution is to properly encapsulate system-dependant code so that whatever version statement you need, is all in one place. Also when you have to hack 10 different macros together to invent a feature your language doesn't have, you've got a problem, but this is much less of a concern in D than C++. When even D gurus writing D compilers have to hack solutions together with static if to get by, its time to re-evaluate the situation. BitMost things aside from straight up version([!]condition [op condition... [op condition...]) { ... } [else { ... }] are going to lead to surprising behavior, bad code, and gnashing of teeth. We shouldn't have to resort to macros to do this.
Dec 13 2018