Thread overview | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
May 10, 2016 Version block "conditions" with logical operators | ||||
---|---|---|---|---|
| ||||
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 Re: Version block "conditions" with logical operators | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tomer Filiba | 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? > > -tomer This 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 Re: Version block "conditions" with logical operators | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tomer Filiba | 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 trick
Well, 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 Re: Version block "conditions" with logical operators | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tomer Filiba | 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 Re: Version block "conditions" with logical operators | ||||
---|---|---|---|---|
| ||||
Posted in reply to Joakim | 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 pointers > 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 ... > 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 Re: Version block "conditions" with logical operators | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johan Engelen | 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-L45
A 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 Re: Version block "conditions" with logical operators | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tomer Filiba | 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 Re: Version block "conditions" with logical operators | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tomer Filiba | On 5/10/16 2:48 PM, Tomer Filiba wrote:
> 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 trick
>
> Well, 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
Not if we put it in the standard library :o). -- Andrei
|
May 11, 2016 Re: Version block "conditions" with logical operators | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tomer Filiba | 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: >> Alternatively, an isVersion(x) predicate that I could use in a static if could do the trick > > Well, 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 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) { /* ... */ } ----------------------------------------------------- artur |
May 11, 2016 Re: Version block "conditions" with logical operators | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tomer Filiba | 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? > > -tomer Still 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 |
Copyright © 1999-2021 by the D Language Foundation