www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Good examples of version() algebra in real code

reply Dennis <dkorpel gmail.com> writes:
D's version() statement deliberately does not allow composing 
version conditions with boolean operators `! || &&`, in order to 
avoid C's `#ifdef` hell. This is a controversial design decision 
though, because some people don't like the resulting verbosity 
you sometimes get. Discussions about this come up now and then, 
see for example [Issue 
7417](https://issues.dlang.org/show_bug.cgi?id=7417) and its 
duplicates.

The most recent incarnation of this comes from this Phobos PR 
proposing a library solution:
[std.compiler.Version](https://github.com/dlang/phobos/pull/8750)

```D
import std.compiler;

static if (Version.D_InlineAsm_X86 || Version.D_InlineAsm_X86_64)
{
     version = UseX86Assembly;
}
```

I don't expect this to get approval though, I said in the PR 
discussion:

 I'll bring this up in the next DLF monthly meeting, but without 
 new compelling arguments, I don't expect a different outcome. 
 If you can demonstrate problems (other than it not looking 
 nice) in existing projects that the current logic causes, 
 you'll have a stronger case.
So far I haven't received any real code examples, so I'm asking here: Do you have any examples of existing projects (on github, dub, etc.) that either: - demonstrate version algebra done well - use a `Version`-like template successfully - have real problems with existing `version()` statements (besides 'it looks ugly') Please reply with links and don't rekindle the old arguments. I can't stop you, but know that it will only be counter-productive.
May 21 2023
next sibling parent reply Guillaume Piolat <first.last spam.org> writes:
On Sunday, 21 May 2023 at 18:43:32 UTC, Dennis wrote:
 
 - have real problems with existing `version()` statements 
 (besides 'it looks ugly')
No big problem, but sometimes you need to do: version(X86) version = AnyX86; version(X86_64) version = AnyX86; or version (OSX) version = Darwin; else version (iOS) version = Darwin; else version (TVOS) version = Darwin; else version (WatchOS) version = Darwin; or version (D_InlineAsm_X86) version = UseX86Assembly; version (D_InlineAsm_X86_64) version = UseX86Assembly; and those are the only case I remember being a tiny bit annoyed at `version`. I wouldn't use the above library solution to save one import.
May 21 2023
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/21/23 3:09 PM, Guillaume Piolat wrote:
 On Sunday, 21 May 2023 at 18:43:32 UTC, Dennis wrote:
 - have real problems with existing `version()` statements (besides 'it 
 looks ugly')
No big problem, but sometimes you need to do:     version(X86)         version = AnyX86;     version(X86_64)         version = AnyX86; or     version (OSX)         version = Darwin;     else version (iOS)         version = Darwin;     else version (TVOS)         version = Darwin;     else version (WatchOS)         version = Darwin; or     version (D_InlineAsm_X86)         version = UseX86Assembly;     version (D_InlineAsm_X86_64)         version = UseX86Assembly; and those are the only case I remember being a tiny bit annoyed at `version`. I wouldn't use the above library solution to save one import.
One of the largest problems with this scheme is it needs to be repeated in every module that uses e.g. `version(Darwin)`. -Steve
May 22 2023
parent Guillaume Piolat <first.last spam.org> writes:
On Monday, 22 May 2023 at 12:41:24 UTC, Steven Schveighoffer 
wrote:
 One of the largest problems with this scheme is it needs to be 
 repeated in every module that uses e.g. `version(Darwin)`.

 -Steve
Yes, maybe add those 3 common version identifiers directly, which doesn't change the design of `version`. Also maybe Hipreme's idea avoids the #ifdef hell problem (abondance of names and double negations).
 Maybe if there was a construct for allowing **only version 
 declaration** with boolean operators like:
`version RelaxedSystems = version(Windows && linux && !OSX)` (it would not be global as the `version` is right now. i.e: not allow this syntax to be used standalone.
May 22 2023
prev sibling next sibling parent max haughton <maxhaton gmail.com> writes:
On Sunday, 21 May 2023 at 18:43:32 UTC, Dennis wrote:
 D's version() statement deliberately does not allow composing 
 version conditions with boolean operators `! || &&`, in order 
 to avoid C's `#ifdef` hell. This is a controversial design 
 decision though, because some people don't like the resulting 
 verbosity you sometimes get. Discussions about this come up now 
 and then, see for example [Issue 
 7417](https://issues.dlang.org/show_bug.cgi?id=7417) and its 
 duplicates.

 The most recent incarnation of this comes from this Phobos PR 
 proposing a library solution:
 [std.compiler.Version](https://github.com/dlang/phobos/pull/8750)

 ```D
 import std.compiler;

 static if (Version.D_InlineAsm_X86 || 
 Version.D_InlineAsm_X86_64)
 {
     version = UseX86Assembly;
 }
 ```

 I don't expect this to get approval though, I said in the PR 
 discussion:

 I'll bring this up in the next DLF monthly meeting, but 
 without new compelling arguments, I don't expect a different 
 outcome. If you can demonstrate problems (other than it not 
 looking nice) in existing projects that the current logic 
 causes, you'll have a stronger case.
So far I haven't received any real code examples, so I'm asking here: Do you have any examples of existing projects (on github, dub, etc.) that either: - demonstrate version algebra done well - use a `Version`-like template successfully - have real problems with existing `version()` statements (besides 'it looks ugly')
It's not bad to try and make good look good. Most programming language design decisions boil down to some kind of aesthetically driven heuristic. Current state of affairs is oppressive because it makes common cases expensive. That being said a lot of `version` usage shouldn't exist. Let the compiler constant fold the details for you so your code ports to new architecture/cross target more easily
May 21 2023
prev sibling next sibling parent reply Hipreme <msnmancini hotmail.com> writes:
On Sunday, 21 May 2023 at 18:43:32 UTC, Dennis wrote:
 D's version() statement deliberately does not allow composing 
 version conditions with boolean operators `! || &&`, in order 
 to avoid C's `#ifdef` hell. This is a controversial design 
 decision though, because some people don't like the resulting 
 verbosity you sometimes get. Discussions about this come up now 
 and then, see for example [Issue 
 7417](https://issues.dlang.org/show_bug.cgi?id=7417) and its 
 duplicates.

 The most recent incarnation of this comes from this Phobos PR 
 proposing a library solution:
 [std.compiler.Version](https://github.com/dlang/phobos/pull/8750)

 ```D
 import std.compiler;

 static if (Version.D_InlineAsm_X86 || 
 Version.D_InlineAsm_X86_64)
 {
     version = UseX86Assembly;
 }
 ```

 I don't expect this to get approval though, I said in the PR 
 discussion:

 I'll bring this up in the next DLF monthly meeting, but 
 without new compelling arguments, I don't expect a different 
 outcome. If you can demonstrate problems (other than it not 
 looking nice) in existing projects that the current logic 
 causes, you'll have a stronger case.
So far I haven't received any real code examples, so I'm asking here: Do you have any examples of existing projects (on github, dub, etc.) that either: - demonstrate version algebra done well - use a `Version`-like template successfully - have real problems with existing `version()` statements (besides 'it looks ugly') Please reply with links and don't rekindle the old arguments. I can't stop you, but know that it will only be counter-productive.
Keep in mind that I have found plenty of codes when defining a `version` based on `static if`. This bug probably occurs for them being parsed at different stages of the compiler, I would be using that if weren't for the bugs. Right now I've come to understand that using feature based versions instead of real versions really makes a lot of difference. But as Guillaume pointed out, there is still this other problem of defining a feature based on multiple platforms and this solution doesn't really make one write a lot less, so I still find this solution lacking for our problem which makes me wonder if there really exists a good solution for that.
May 21 2023
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/21/2023 7:01 PM, Hipreme wrote:
 Right now I've come to understand that using feature based versions instead of 
 real versions really makes a lot of difference. But as Guillaume pointed out, 
 there is still this other problem of defining a feature based on multiple 
 platforms and this solution doesn't really make one write a lot less, so I
still 
 find this solution lacking for our problem which makes me wonder if there
really 
 exists a good solution for that.
version(linux) enum ExtraFunctionality = true; else version(OSX) enum ExtraFunctionality = true; else version(Windows) enum ExtraFunctionality = false; else static assert(0, "system not accounted for"); The static assert is there because a very common failure of #ifdef hell is to have defaults that botch things up when a new version is added. This happens sometimes in the druntime imports, when I discover them I add the static assert. There are still other ways to do it: ``` import extra; void foo() { extraFunctionality(); } ``` ``` module extra; void extraFunctionality() { version(linux) doit(); else version(OSX) doit(); else version(Windows) { } else static assert(0, "system not accounted for"); } ``` Another way is to write a "personality module" for each operating system, and then import the right one: ``` module extra; version (linux) import extraLinux; else version (OSX) import extraOSX; ... and so on ... ``` Personally, I like to make the core code version-independent and OS-independent and hide the variances in separate modules. Isn't foo() clean looking?
May 22 2023
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
```
version(linux)         enum ExtraFunctionality = true;
else version(OSX)      enum ExtraFunctionality = true;
else version(Windows)  enum ExtraFunctionality = false;
else static assert(0, "system not accounted for");
```

(forgot to use Markdown! Oops!)
May 22 2023
parent reply Hipreme <msnmancini hotmail.com> writes:
On Monday, 22 May 2023 at 08:23:31 UTC, Walter Bright wrote:
 ```
 version(linux)         enum ExtraFunctionality = true;
 else version(OSX)      enum ExtraFunctionality = true;
 else version(Windows)  enum ExtraFunctionality = false;
 else static assert(0, "system not accounted for");
 ```

 (forgot to use Markdown! Oops!)
When I programmed for Haxe, it did have a feature which you could for example name your file based on the target OS: Imagine we had the `module input`. Since all OS have a different way to get input, we can basically separate them as you just said, by files. How Haxe solves that is by letting users define a special file name such as: `input.windows.hx` and `input.javascript.hx`. Whenever you import that file for usage, it will automatically import the correct file based on your target. I did use that feature and in my experience: This is quite cool and can lead to a single file to read without having any extra concern. The problem is that it did generated a bit of code duplication. Which could be solved by putting the common code in another file.
May 22 2023
parent Walter Bright <newshound2 digitalmars.com> writes:
On 5/22/2023 4:12 AM, Hipreme wrote:
 Imagine we had the `module input`. Since all OS have a different way to get 
 input, we can basically separate them as you just said, by files. How Haxe 
 solves that is by letting users define a special file name such as:
 `input.windows.hx` and `input.javascript.hx`. Whenever you import that file
for 
 usage, it will automatically import the correct file based on your target. I
did 
 use that feature and in my experience: This is quite cool and can lead to a 
 single file to read without having any extra concern. The problem is that it
did 
 generated a bit of code duplication. Which could be solved by putting the
common 
 code in another file.
Yup, that works well. A nice dividend is, you want to port to a new platform? The only code needed to be looked at is the personality module. Much better than it being peppered through the source code, and even worse, be unfindable because of the use of defaults.
May 22 2023
prev sibling next sibling parent reply Max Samukha <maxsamukha gmail.com> writes:
On Monday, 22 May 2023 at 08:21:50 UTC, Walter Bright wrote:

 Personally, I like to make the core code version-independent 
 and OS-independent and hide the variances in separate modules. 
 Isn't foo() clean looking?
I sense echoes of the infamous "Clean Code" debate. Why can't we just let the programmer decide whether to put the versions inline or to hide them behind an abstraction?
May 22 2023
parent Walter Bright <newshound2 digitalmars.com> writes:
On 5/22/2023 1:40 AM, Max Samukha wrote:
 I sense echoes of the infamous "Clean Code" debate. Why can't we just let the 
 programmer decide whether to put the versions inline or to hide them behind an 
 abstraction?
Blind adherence to any nostrum leads to hell. However, I'm pleased that the dlang code has not devolved into version hell, which every long term C and C++ project I'm familiar with descended into.
May 22 2023
prev sibling next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 22/05/2023 8:21 PM, Walter Bright wrote:
 The static assert is there because a very common failure of #ifdef hell 
 is to have defaults that botch things up when a new version is added.
If you want to be principled about it, one way to consider it is that not having an else branch (even if empty) should be an error. Because you clearly didn't think about the multiplicative issues of the versions. Regardless, or'ing isn't the issue, its when you and versions that you get an explosion of multiplicative issues. An option could be to use comma instead of ``||`` to handle or'ing. That way people won't be so tempted to "just extend it" to other operators like and.
May 22 2023
parent Walter Bright <newshound2 digitalmars.com> writes:
On 5/22/2023 1:49 AM, Richard (Rikki) Andrew Cattermole wrote:
 If you want to be principled about it, one way to consider it is that not
having 
 an else branch (even if empty) should be an error. Because you clearly didn't 
 think about the multiplicative issues of the versions.
Sometimes, something really is a Windows-only thang. But when it's a Windows or OSX thing, enumeration of all the platforms is the way to go.
 An option could be to use comma instead of || to handle or'ing.
That goes to version hell, too. Some of this remains in the backend, and it isn't pretty.
May 22 2023
prev sibling next sibling parent reply Hipreme <msnmancini hotmail.com> writes:
On Monday, 22 May 2023 at 08:21:50 UTC, Walter Bright wrote:
 On 5/21/2023 7:01 PM, Hipreme wrote:
 Right now I've come to understand that using feature based 
 versions instead of real versions really makes a lot of 
 difference. But as Guillaume pointed out, there is still this 
 other problem of defining a feature based on multiple 
 platforms and this solution doesn't really make one write a 
 lot less, so I still find this solution lacking for our 
 problem which makes me wonder if there really exists a good 
 solution for that.
version(linux) enum ExtraFunctionality = true; else version(OSX) enum ExtraFunctionality = true; else version(Windows) enum ExtraFunctionality = false; else static assert(0, "system not accounted for"); The static assert is there because a very common failure of #ifdef hell is to have defaults that botch things up when a new version is added. This happens sometimes in the druntime imports, when I discover them I add the static assert. There are still other ways to do it: ``` import extra; void foo() { extraFunctionality(); } ``` ``` module extra; void extraFunctionality() { version(linux) doit(); else version(OSX) doit(); else version(Windows) { } else static assert(0, "system not accounted for"); } ``` Another way is to write a "personality module" for each operating system, and then import the right one: ``` module extra; version (linux) import extraLinux; else version (OSX) import extraOSX; ... and so on ... ``` Personally, I like to make the core code version-independent and OS-independent and hide the variances in separate modules. Isn't foo() clean looking?
Yes, I do understand. Although I prefer `static assert` to not be used, but the runtime `assert`. I have done a port of the druntime and the `static assert` usage really is a pain since there is just a plain lot of code which is not used by me, but only for its existence, it causes a compilation error. I think the feature based is cleaner to read most of the time (and scalable), I have done a good refactor in a lot of D code already using that, and IMO, it did done wonders into making the code intention crystal clear even for non maintainers. This is a thing which I've come to understand the decision of not allowing boolean operators on `version`. Maybe if there was a construct for allowing **only version declaration** with boolean operators like: `version RelaxedSystems = version(Windows && linux && !OSX)` (it would not be global as the `version` is right now. i.e: not allow this syntax to be used standalone. So, the operators aren't really the hell that causes the `#ifdef` hell as you said. The problem are 2: 1: They being defined over all files. While trying to port newlibc, I've come to find a type to be defined over 6 files. Which meant I really went jumping from a file to file until I was able to find how the type were defined. This is a real problem since the type is not self contained so it is super hard to look. How to solve that: D has solved! Just make the `version =` not spam into multiple files. 2: Operators: they don't really make sense when other people are looking into them, which is solved by having the feature named, so, enforcing the naming to use the operators could be a problem solving in the syntax. Since they aren't global, they are painful to keep writing all the time the same thing (I've tried doing that on directx-d binding and omg, I basically got a 8 line headers in almost all files, sure, it is easier to read than C, but it was painful writing them).
May 22 2023
parent Walter Bright <newshound2 digitalmars.com> writes:
On 5/22/2023 4:06 AM, Hipreme wrote:
 Yes, I do understand. Although I prefer `static assert` to not be used, but
the 
 runtime `assert`. I have done a port of the druntime and the `static assert` 
 usage really is a pain since there is just a plain lot of code which is not
used 
 by me, but only for its existence, it causes a compilation error.
Runtime assert doesn't work at module scope. Also, it's usually better to catch porting errors at compile time, rather than after the code was shipped.
 I think the feature based is cleaner to read most of the time (and scalable),
I 
 have done a good refactor in a lot of D code already using that, and IMO, it
did 
 done wonders into making the code intention crystal clear even for non 
 maintainers. This is a thing which I've come to understand the decision of not 
 allowing boolean operators on `version`. Maybe if there was a construct for 
 allowing **only version declaration** with boolean operators like:
 `version RelaxedSystems = version(Windows && linux && !OSX)` (it would not be 
 global as the `version` is right now. i.e: not allow this syntax to be used 
 standalone.
As I mentioned elsewhere, that goes wrong, too.
 So, the operators aren't really the hell that causes the `#ifdef` hell as you 
 said. The problem are 2:
 
 1: They being defined over all files. While trying to port newlibc, I've come
to 
 find a type to be defined over 6 files. Which meant I really went jumping from
a 
 file to file until I was able to find how the type were defined. This is a
real 
 problem since the type is not self contained so it is super hard to look. How
to 
 solve that: D has solved! Just make the `version =` not spam into multiple
files.
Yup. D does not "import" versions from other modules. This was another crucial design decision that has paid off handsomely. How miserable it is in C to figure out where a #define is coming from in the typical rat's nests of #include's, or even if it is #define'd at all.
 2: Operators: they don't really make sense when other people are looking into 
 them, which is solved by having the feature named, so, enforcing the naming to 
 use the operators could be a problem solving in the syntax.
Most people read code a hundred times more than they write code, so being a bit verbose to improve reading is a worthwhile tradeoff.
 Since they aren't
 global, they are painful to keep writing all the time the same thing (I've
tried
 doing that on directx-d binding and omg, I basically got a 8 line headers in
 almost all files, sure, it is easier to read than C, but it was painful writing
 them).
The technique, as I mentioned in the upstream post, is to have the feature versions in one file, have `extraFunctionality()` defined as doing something or a noop in that file, and just call `extraFunctionality()` elsewhere. I should write an article about this.
May 22 2023
prev sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Monday, 22 May 2023 at 08:21:50 UTC, Walter Bright wrote:
 Personally, I like to make the core code version-independent 
 and OS-independent and hide the variances in separate modules. 
 Isn't foo() clean looking?
http://dpldocs.info/this-week-in-d/Blog.Posted_2023_02_20.html#static-assert-patterns-arguably-harmful-for-porting
May 22 2023
next sibling parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Monday, 22 May 2023 at 11:23:32 UTC, Adam D Ruppe wrote:
 On Monday, 22 May 2023 at 08:21:50 UTC, Walter Bright wrote:
 Personally, I like to make the core code version-independent 
 and OS-independent and hide the variances in separate modules. 
 Isn't foo() clean looking?
http://dpldocs.info/this-week-in-d/Blog.Posted_2023_02_20.html#static-assert-patterns-arguably-harmful-for-porting
I agree with you that having the option of using run-time guards like `assert(0)` / `throw new NotImplementedEx()` and even using empty declarations at compile-time is very convenient in practice to get going with a port. On the other hand, I also find a great amount in being able to get an almost complete list of things that I need to fix at compile-time in terms of planning my work. Based on your blog post it would seem that two approaches are opposite to each other, but I think we should find a way to have our cake and eat it. A better solution (in that it works with the existing code using `static assert`s) would be having fully lazy compilation model further along the lines of `dmd -i`: starting from set of root symbols (e.g. `main`, `unittest` when unit tests are enabled, and functions explicitly marked as `export`) the compiler should semantically analyse only the declarations which are referenced (directly or indirectly) from the root set. That way, if any symbol (be it `enum`, `struct`, function, etc.) is not referenced, it won't analysed and the `static assert` won't be hit.
May 22 2023
next sibling parent Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Monday, 22 May 2023 at 11:46:10 UTC, Petar Kirov [ZombineDev] 
wrote:
 [..]

 A better solution (in that it works with the existing code 
 using `static assert`s) would be having fully lazy compilation 
 model further along the lines of `dmd -i`:
 starting from set of root symbols (e.g. `main`, `unittest` when 
 unit tests are enabled, and functions explicitly marked as 
 `export`) the compiler should semantically analyse only the 
 declarations which are referenced (directly or indirectly) from 
 the root set. That way, if any symbol (be it `enum`, `struct`, 
 function, etc.) is not referenced, it won't analysed and the 
 `static assert` won't be hit.
This needs to be a different, explicitly opt-in compilation mode, because it would change the meaning of existing programs using introspectio language features like `__traits(allMembers, X)`, `is(X)`, `__traits(compiles, E)`.
May 22 2023
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 22.05.23 13:46, Petar Kirov [ZombineDev] wrote:
 On Monday, 22 May 2023 at 11:23:32 UTC, Adam D Ruppe wrote:
 On Monday, 22 May 2023 at 08:21:50 UTC, Walter Bright wrote:
 Personally, I like to make the core code version-independent and 
 OS-independent and hide the variances in separate modules. Isn't 
 foo() clean looking?
http://dpldocs.info/this-week-in-d/Blog.Posted_2023_02_20.html#static-assert-patterns-arguably-harmful-for-porting
I agree with you that having the option of using run-time guards like `assert(0)` / `throw new NotImplementedEx()` and even using empty declarations at compile-time is very convenient in practice to get going with a port. On the other hand, I also find a great amount in being able to get an almost complete list of things that I need to fix at compile-time in terms of planning my work.
```d version(Windows) foo(); else version(linux) bar(); else version(fail_early) static assert(0); else assert(0); ``` :o)
May 22 2023
parent Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Monday, 22 May 2023 at 14:10:24 UTC, Timon Gehr wrote:
 On 22.05.23 13:46, Petar Kirov [ZombineDev] wrote:
 On Monday, 22 May 2023 at 11:23:32 UTC, Adam D Ruppe wrote:
 On Monday, 22 May 2023 at 08:21:50 UTC, Walter Bright wrote:
 Personally, I like to make the core code version-independent 
 and OS-independent and hide the variances in separate 
 modules. Isn't foo() clean looking?
http://dpldocs.info/this-week-in-d/Blog.Posted_2023_02_20.html#static-assert-patterns-arguably-harmful-for-porting
I agree with you that having the option of using run-time guards like `assert(0)` / `throw new NotImplementedEx()` and even using empty declarations at compile-time is very convenient in practice to get going with a port. On the other hand, I also find a great amount in being able to get an almost complete list of things that I need to fix at compile-time in terms of planning my work.
```d version(Windows) foo(); else version(linux) bar(); else version(fail_early) static assert(0); else assert(0); ``` :o)
Two issues: * Requires changing all existing code * Doesn't work for declarations (e.g. defining an `enum`, `struct`, etc. at module scope)
May 23 2023
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 5/22/2023 4:23 AM, Adam D Ruppe wrote:
 http://dpldocs.info/this-week-in-d/Blog.Posted_2023_02_20.html#static-assert-patterns-arguably-harmful-for-porting
A good article!
May 22 2023
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
I don't have links, it was a long time ago, but there was a time when someone 
introduced enums to druntime modules and used them with non-trivial static if 
expressions. People started extending this, and it soon became quite a tangle
of 
some static ifs depending on other static ifs and the declarations of the enums 
became embedded in static ifs and then, inevitably, circular imports came into
play.

Then, the whole thing reached a point where nobody could figure out whether 
particular static ifs were being triggered or not. The problem got dumped in my 
lap, and I yanked out all the static if's and replaced them with trivial logic.

In getting ImportC to work with system .h files, written by the best C experts 
on the planet, I've been re-acquainted with #ifdef hell.

I used to write #ifdef hell myself. It's very seductive.

So, yes, you can use static if and enums to implement version hell. But not in 
any official Dlang repositories.
May 22 2023
prev sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Sunday, 21 May 2023 at 18:43:32 UTC, Dennis wrote:
 D's version() statement deliberately does not allow composing 
 version conditions with boolean operators `! || &&`, in order 
 to avoid C's `#ifdef` hell. This is a controversial design 
 decision though, because some people don't like the resulting 
 verbosity you sometimes get. Discussions about this come up now 
 and then, see for example [Issue 
 7417](https://issues.dlang.org/show_bug.cgi?id=7417) and its 
 duplicates.

 The most recent incarnation of this comes from this Phobos PR 
 proposing a library solution:
 [std.compiler.Version](https://github.com/dlang/phobos/pull/8750)

 ```D
 import std.compiler;

 static if (Version.D_InlineAsm_X86 || 
 Version.D_InlineAsm_X86_64)
 {
     version = UseX86Assembly;
 }
 ```

 I don't expect this to get approval though, I said in the PR 
 discussion:

 I'll bring this up in the next DLF monthly meeting, but 
 without new compelling arguments, I don't expect a different 
 outcome. If you can demonstrate problems (other than it not 
 looking nice) in existing projects that the current logic 
 causes, you'll have a stronger case.
So far I haven't received any real code examples, so I'm asking here: Do you have any examples of existing projects (on github, dub, etc.) that either: - demonstrate version algebra done well - use a `Version`-like template successfully - have real problems with existing `version()` statements (besides 'it looks ugly') Please reply with links and don't rekindle the old arguments. I can't stop you, but know that it will only be counter-productive.
One thing that is not mentioned is the grammar of version algebra...what would be allowed ? Do we want things like version(mixin(someCtfeCall(()) How would be handled the fact that enum BigEndian = 0.123; is ATM legal, i.e identifiers can be both expressions and sealed version identifiers ? There are already bugs caused by the fact that `static if`s can introduce `version`s... it's probably not worth introducing version algebra until those get fixed.
May 23 2023
parent Basile B. <b2.temp gmx.com> writes:
On Tuesday, 23 May 2023 at 10:01:37 UTC, Basile B. wrote:
 On Sunday, 21 May 2023 at 18:43:32 UTC, Dennis wrote:
 [...]

 One thing that is not mentioned is the grammar of version 
 algebra...what would be allowed ? Do we want things like

     version(mixin(someCtfeCall(())

 How would be handled the fact that

     enum BigEndian = 0.123;

 is ATM legal, i.e identifiers can be both expressions and 
 sealed version identifiers ?

 There are already bugs caused by the fact that `static if`s can 
 introduce `version`s... it's probably not worth introducing 
 version algebra until those get fixed.
image for the children : https://imgflip.com/i/7mropf
May 23 2023