www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - version(number) is completely useless

reply Hipreme <msnmancini hotmail.com> writes:
version(number) actually contains something really nice on it. 
But it is useless.

For example: version(3) would actually declare version(2) and 
version(1).

The problem is that these doesn't mean anything at all, but they 
have this property of waterfall. Which is totally missing in D 
right now. Take this as an example:

```d

version(V1_3)
     version = V1_2;
version(V1_2)
     version = V1_1;
version(V1_1)
     version = V1_0;
```

I need to do this. **per file**. This is such a boilerplate code 
that could get a lot nicer if we had some kind of versioning 
syntax. For example `version(V.1.3)`. We could even get:
`version(SDL.2.5)`. Which would declare everything down to SDL.2.0


Obviously this feature is meaningless to small projects
Jul 19 2022
next sibling parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Tuesday, 19 July 2022 at 22:30:28 UTC, Hipreme wrote:
 version(number) actually contains something really nice on it. 
 But it is useless.

 For example: version(3) would actually declare version(2) and 
 version(1).
IMO it is completely useless: what does "3" mean? what is relationship between "3" in my package and "3" in dependency? what is relationship between "3" in different sources within the same package?
 The problem is that these doesn't mean anything at all, but 
 they have this property of waterfall. Which is totally missing 
 in D right now. Take this as an example:

 ```d

 version(V1_3)
     version = V1_2;
 version(V1_2)
     version = V1_1;
 version(V1_1)
     version = V1_0;
 ```
I don't like it - why can't we just write this instead? ```d version(V1 >= 3) pragma(msg, "newest version"); else version(V1 >= 2) pragma(msg, "old version"); else pragma(msg, "obsolete version"); ``` But having this would mean that D has two ways to express the same things: `version` and `static if` because that code is the same as: ```d static if(V1 >= 3) pragma(msg, "newest version"); else static if(V1 >= 2) pragma(msg, "old version"); else pragma(msg, "obsolete version"); ```
 I need to do this. **per file**. This is such a boilerplate 
 code that could get a lot nicer if we had some kind of 
 versioning syntax. For example `version(V.1.3)`. We could even 
 get:
 `version(SDL.2.5)`. Which would declare everything down to 
 SDL.2.0
Again, why can't it be `version(V >= 1.3)` or `static if(SDL >= 2.5)`?
Jul 19 2022
parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
I actually have a question since this topic is brought up:
What is conceptual difference between `version(FOO)` and `static 
if(FOO)`? I see `version` is a very limited comparing to `static 
if` - the former checks for "boolean" result (whether an ID is 
defined) while the latter evaluates condition expression.
Jul 19 2022
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/19/22 9:22 PM, Andrey Zherikov wrote:
 I actually have a question since this topic is brought up:
 What is conceptual difference between `version(FOO)` and `static 
 if(FOO)`? I see `version` is a very limited comparing to `static if` - 
 the former checks for "boolean" result (whether an ID is defined) while 
 the latter evaluates condition expression.
version is specifically a replacement for #defines as in C. They are specified mostly on the command line. But also, a version cannot be detected from an imported file -- every module starts with the compilation versions, and that's it. Walter was very averse to the mess that is C preprocessor defines, and wanted something more hygienic. The thing I miss the most for versions is a `version1 or version2` mechanism. I doubt we will ever convince Walter this is a good idea. But in any case, we have the numeric versions, which are 100% useless (because, as you say, they are not scoped to any dependencies), it would make sense to at least make that feature useful. -Steve
Jul 19 2022
next sibling parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 20 July 2022 at 01:34:00 UTC, Steven Schveighoffer 
wrote:
 On 7/19/22 9:22 PM, Andrey Zherikov wrote:
 I actually have a question since this topic is brought up:
 What is conceptual difference between `version(FOO)` and 
 `static if(FOO)`? I see `version` is a very limited comparing 
 to `static if` - the former checks for "boolean" result 
 (whether an ID is defined) while the latter evaluates 
 condition expression.
version is specifically a replacement for #defines as in C. They are specified mostly on the command line.
It's not a full replacement because it doesn't support `-DSOME_DEFINE=5` or `-DANOTHER_DEFINE="some string"`. One of the features which I really miss in D is inability to do these things. This is very largely used in software development for setting compile-time constants from command line. D doesn't support this out of the box (I have to dump a `.d` file with set of `enums` and then include it into the build).
 But also, a version cannot be detected from an imported file -- 
 every module starts with the compilation versions, and that's 
 it.

 Walter was very averse to the mess that is C preprocessor 
 defines, and wanted something more hygienic.
I'm totally for simple and clean solution here but whatever D offers right now is half-baked IMHO.
 The thing I miss the most for versions is a `version1 or 
 version2` mechanism. I doubt we will ever convince Walter this 
 is a good idea.
I don't think that `version1 or version2` is any different than allowing complete conditional expression.
 But in any case, we have the numeric versions, which are 100% 
 useless (because, as you say, they are not scoped to any 
 dependencies), it would make sense to at least make that 
 feature useful.
I don't see how raw numbers can be useful. Could you clarify your idea?
Jul 19 2022
next sibling parent jfondren <julian.fondren gmail.com> writes:
On Wednesday, 20 July 2022 at 02:10:21 UTC, Andrey Zherikov wrote:
 It's not a full replacement because it doesn't support 
 `-DSOME_DEFINE=5` or `-DANOTHER_DEFINE="some string"`.

 One of the features which I really miss in D is inability to do 
 these things. This is very largely used in software development 
 for setting compile-time constants from command line. D doesn't 
 support this out of the box (I have to dump a `.d` file with 
 set of `enums` and then include it into the build).
And that works, right? When you definitely need the feature, enough to live with a build-system burden like this, then you can have it. And when you don't definitely need it, D's `version` feature doesn't let you casually, effortlessly, create an impossible to understand version soup. Meanwhile, D makes it trivially easy to add a unit test whenever you want, and in some other languages unit testing is a feature that requires you to bear the burden of a more complex build system. You can see the opinions of the language designers. Testing is so important that even a throwaway function posted to this forum can have a unittest{} with it. Elaborate build-time configuration is so detested that you have to ignore the relevant language feature and roll your own alternative to it.
Jul 19 2022
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/19/22 10:10 PM, Andrey Zherikov wrote:
 On Wednesday, 20 July 2022 at 01:34:00 UTC, Steven Schveighoffer wrote:
 On 7/19/22 9:22 PM, Andrey Zherikov wrote:
 I actually have a question since this topic is brought up:
 What is conceptual difference between `version(FOO)` and `static 
 if(FOO)`? I see `version` is a very limited comparing to `static if` 
 - the former checks for "boolean" result (whether an ID is defined) 
 while the latter evaluates condition expression.
version is specifically a replacement for #defines as in C. They are specified mostly on the command line.
It's not a full replacement because it doesn't support `-DSOME_DEFINE=5` or `-DANOTHER_DEFINE="some string"`.
Yes, and actually, this is not something I miss terribly. One place where I do miss it is communicating something like git version information to the compiler. The only way to do this is to pre-build a module for it.
 The thing I miss the most for versions is a `version1 or version2` 
 mechanism. I doubt we will ever convince Walter this is a good idea.
I don't think that `version1 or version2` is any different than allowing complete conditional expression.
`version(a) version(b)` accomplishes a && b. But a || b is just a complete pain to write.
 
 But in any case, we have the numeric versions, which are 100% useless 
 (because, as you say, they are not scoped to any dependencies), it 
 would make sense to at least make that feature useful.
I don't see how raw numbers can be useful. Could you clarify your idea?
The proposal here (I think) is that if you define version `MyLibrary.5` then `version(MyLibrary.4)` or `version(MyLibrary.1)` all are enabled. What the current system does is worthless, because `version(5)` has no meaning. If we scope the numbers to be within a specific project, then that project has the ability to define what those things mean, and you can just define one version on the command line. -Steve
Jul 19 2022
next sibling parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 20 July 2022 at 02:44:28 UTC, Steven Schveighoffer 
wrote:
 `version(a) version(b)` accomplishes a && b. But a || b is just 
 a complete pain to write.
Does this solve the issue? ```d version(a) version = a_or_b; version(b) version = a_or_b; version(a_or_b) // do whatever you need ```
 But in any case, we have the numeric versions, which are 100% 
 useless (because, as you say, they are not scoped to any 
 dependencies), it would make sense to at least make that 
 feature useful.
I don't see how raw numbers can be useful. Could you clarify your idea?
The proposal here (I think) is that if you define version `MyLibrary.5` then `version(MyLibrary.4)` or `version(MyLibrary.1)` all are enabled. What the current system does is worthless, because `version(5)` has no meaning. If we scope the numbers to be within a specific project, then that project has the ability to define what those things mean, and you can just define one version on the command line.
Scoping to a project doesn't always provide the meaning: if I have a library that does network communication then what is this version number - library version, protocol version or something else?
Jul 19 2022
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/19/22 11:54 PM, Andrey Zherikov wrote:
 On Wednesday, 20 July 2022 at 02:44:28 UTC, Steven Schveighoffer wrote:
 `version(a) version(b)` accomplishes a && b. But a || b is just a 
 complete pain to write.
Does this solve the issue? ```d version(a)     version = a_or_b; version(b)     version = a_or_b; version(a_or_b)     // do whatever you need ```
That's the pain I'm referring to.
 The proposal here (I think) is that if you define version 
 `MyLibrary.5` then `version(MyLibrary.4)` or `version(MyLibrary.1)` 
 all are enabled.

 What the current system does is worthless, because `version(5)` has no 
 meaning. If we scope the numbers to be within a specific project, then 
 that project has the ability to define what those things mean, and you 
 can just define one version on the command line.
Scoping to a project doesn't always provide the meaning: if I have a library that does network communication then what is this version number - library version, protocol version or something else?
version(MyLibrary.5) ... // library version version(MyLibrary_protocol.5) ... // protocol version. -Steve
Jul 20 2022
parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 20 July 2022 at 13:49:40 UTC, Steven Schveighoffer 
wrote:
 version(MyLibrary.5) ... // library version
 version(MyLibrary_protocol.5) ... // protocol version.
What I don't like here is an assumption that `MyLibrary.5` is compatible with `MyLibrary.4`,`MyLibrary.3` etc. This might not be the case: versions might be backward incompatible so you will have to do `version(MyLibrary.5 && !MyLibrary.4 && !MyLibrary.3 && !MyLibrary.2 && !MyLibrary.1)`. And here are the problems: we don't wave `&&` (yes, you can substitute it with multiple `version`) and `!` (you have to do `version(bla) {} else {...}`). All these workarounds keep me away from using `version` - the only thing I use is `version(unittest)`.
Jul 20 2022
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Wednesday, 20 July 2022 at 14:37:59 UTC, Andrey Zherikov wrote:

 What I don't like here is an assumption that `MyLibrary.5` is 
 compatible with `MyLibrary.4`,`MyLibrary.3` etc. This might not 
 be the case: versions might be backward incompatible so you 
 will have to do `version(MyLibrary.5 && !MyLibrary.4 && 
 !MyLibrary.3 && !MyLibrary.2 && !MyLibrary.1)`. And here are 
 the problems: we don't wave `&&` (yes, you can substitute it 
 with multiple `version`) and `!` (you have to do `version(bla) 
 {} else {...}`). All these workarounds keep me away from using 
 `version` - the only thing I use is `version(unittest)`.
You can use version in conjunction with enums as I do in my bindbc packages, e.g. https://github.com/BindBC/bindbc-opengl/blob/master/source/bindbc/opengl/config.d. Then you can use whichever logical operators you want on the enums with static if to test for library versions at compile time.
Jul 20 2022
parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 20 July 2022 at 14:46:40 UTC, Mike Parker wrote:
 You can use version in conjunction with enums as I do in my 
 bindbc packages, e.g. 
 https://github.com/BindBC/bindbc-opengl/blob/master/source/bindbc/opengl/config.d.

 Then you can use whichever logical operators you want on the 
 enums with static if to test for library versions at compile 
 time.
I'm not saying that it's impossible, there is a workaround. But why should we have workarounds if we can have better support from the language and compiler? Regarding your example, IMHO there is no difference for your users to do `dmd -version GL_46` or `dmd -define GLSupport.gl46` but the ability to set `GLSupport.gl46` constant from command line will simplify your code (your simply won't need `config.d` at all).
Jul 20 2022
prev sibling next sibling parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
Don't get me wrong, I understand why Walter doesn't want to bring 
`#define`/`#ifdef`/`#if`/`#undef` into D and I agree with him. 
Let's take a look at them:

`#undef`:
There is no such a thing in D - you can't undef a symbol. This 
effectively removes the mess referenced in this thread (at least 
one of its flavor).

`#define`:
It's used to define macroses and compile-time constants. D offers 
template engine for the former and enums for the latter. They 
work perfectly except that I'm not able to set compile-time 
constants from compiler command line (as I mentioned earlier).

`#ifdef`/`#if`:
These are used for conditional compilation. D offers `version` 
and `static if` for these. To be precise: `#ifdef` == `version` 
and `#if` == `static if`.
Since `version` checks whether a symbol is defined only and this 
can be done with `static if(is(typeof(VERSION_ID)))`, the latter 
has all the features that `version` has making it useless IMHO.


There is also another `#ifdef` mess allowed in C:
```c
void func(
#ifdef FOO_INT_PARAM
     int param
#else
     double param
#endif
   )
```

This is not allowed in D due to its syntax - you can use `static 
if` inside function definition. This is also great (IMHO) 
decision.
Jul 20 2022
prev sibling parent reply Hipreme <msnmancini hotmail.com> writes:
On Wednesday, 20 July 2022 at 14:37:59 UTC, Andrey Zherikov wrote:
 On Wednesday, 20 July 2022 at 13:49:40 UTC, Steven 
 Schveighoffer wrote:
 version(MyLibrary.5) ... // library version
 version(MyLibrary_protocol.5) ... // protocol version.
What I don't like here is an assumption that `MyLibrary.5` is compatible with `MyLibrary.4`,`MyLibrary.3` etc. This might not be the case: versions might be backward incompatible so you will have to do `version(MyLibrary.5 && !MyLibrary.4 && !MyLibrary.3 && !MyLibrary.2 && !MyLibrary.1)`. And here are the problems: we don't wave `&&` (yes, you can substitute it with multiple `version`) and `!` (you have to do `version(bla) {} else {...}`). All these workarounds keep me away from using `version` - the only thing I use is `version(unittest)`.
That's why I said about SDL.2.5 It will be compatible to all version until SDL.2.0 That is more than enough for that, specially because breaking changes you could put under a new major versions, and if they're not compatible, you will be declaring another version rather than a number. The problem is exactly that which the best solution right now is doing like Mike has done. I'm only suggesting that because trying to replicate newer version has access to older versions is painful and have lots of boilerplate code which could be solved with metaprogramming. But importing a module for doing this hack doesn't feel very hygienic
Jul 20 2022
parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 20 July 2022 at 16:26:28 UTC, Hipreme wrote:
 That's why I said about SDL.2.5
 It will be compatible to all version until SDL.2.0
 That is more than enough for that, specially because breaking 
 changes you could put under a new major versions, and if 
 they're not compatible, you will be declaring another version 
 rather than a number.
I see one issue with this: you assume semver notion of versions. This might not work for everyone - there are a lot of software that have `<year>` as a major version which has nothing to do with breaking changes.
Jul 20 2022
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/19/2022 7:44 PM, Steven Schveighoffer wrote:
 One place where I do 
 miss it is communicating something like git version information to the
compiler. 
 The only way to do this is to pre-build a module for it.
echo "enum V = `git version`;" > version.d or something like that. (I didn't test it!)
Jul 20 2022
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
On Wednesday, 20 July 2022 at 01:34:00 UTC, Steven Schveighoffer 
wrote:
 The thing I miss the most for versions is a `version1 or 
 version2` mechanism.
You can already do it: ``` struct Version { template opDispatch(string s) { mixin(`version(`~s~`)enum opDispatch=true;else enum opDispatch=false;`); } } static if(Version.OSX || Version.linux){} else{} ```
Jul 20 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
This is very clever, thanks for posting it! I would never have thought of it.

I always enjoy the discovery of these kinds of gems.

But I can't recommend this particular usage, because it isn't the right way to 
do versioning :-)
Jul 23 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/19/2022 6:34 PM, Steven Schveighoffer wrote:
 The thing I miss the most for versions is a `version1 or version2` mechanism.
I 
 doubt we will ever convince Walter this is a good idea.
I know what will happen if that is allowed, and it is not pretty. The idea is to encourage people to work at teasing out just what should be a version and what shouldn't be, not have arithmetic decide what it is. This can be faked with `static if` and some enums. Long ago, some users decided that druntime would be better served using `static if` arithmetic on enums instead of versions. Of course, what quickly emerged was the usual C snarl, and nobody knew what code was being compiled (it was made even worse by mutual dependencies). The problem was dropped in my lap, because nobody could figure it out. I didn't even try to figure it out, I figured out what the versions should be and removed all that `static if` nonsense. If version arithmetic was added, it is guaranteed to produce a coding horror. But by then it will be too late to change our minds, and you and I will be stuck in hell. At least using `static if` on enums as versioning I have managed to discourage, like using operator overloading for I/O. It's also why enums cannot be set on the command line :-)
 But in any case, we have the numeric versions, which are 100% useless
(because, 
 as you say, they are not scoped to any dependencies), it would make sense to
at 
 least make that feature useful.
Yes, the numbers are a failed idea of mine. I'd endorse deprecating them.
Jul 20 2022
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 21 July 2022 at 03:57:31 UTC, Walter Bright wrote:
 At least using `static if` on enums as versioning I have 
 managed to discourage, like using operator overloading for I/O.
Seems like you have encouraged people to avoid using ‘version’ and inventing their own schemes. So you got a many different chaotic expressions of versioning instead of a singular one. How is this easier for library users to deal with? Ideally the language versioning expressions should be the same as the package manager uses. (There is nothing wrong with having operators for I/O and ranges, D would be better if it did provide such.)
Jul 20 2022
parent reply James Blachly <james.blachly gmail.com> writes:
On 7/21/22 1:51 AM, Ola Fosheim Grøstad wrote:
 Seems like you have encouraged people to avoid using ‘version’ and 
 inventing their own schemes. So you got a many different chaotic 
 expressions of versioning instead of a singular one. 
I find this very insightful; the practical consequences of well-meaning policies are often surprising and frequently the complete opposite of the original policy's intent.
Jul 22 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/22/2022 6:31 PM, James Blachly wrote:
 I find this very insightful; the practical consequences of well-meaning
policies 
 are often surprising and frequently the complete opposite of the original 
 policy's intent.
It brings it into the forum where I can explain how to achieve better results than the same old chaotic way C does it. I've lived with the C way for a loooong time. Just take a look at the C system .h files on your system. I know people will treat the version way skeptically at first, but give it a try.
Jul 22 2022
prev sibling next sibling parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Thursday, 21 July 2022 at 03:57:31 UTC, Walter Bright wrote:
 If version arithmetic was added, it is guaranteed to produce a 
 coding horror. But by then it will be too late to change our 
 minds, and you and I will be stuck in hell.

 At least using `static if` on enums as versioning I have 
 managed to discourage, like using operator overloading for I/O. 
 It's also why enums cannot be set on the command line :-)
Unfortunately as you know people don't care about what you discourage or encourage. People just try to express their intent using those language structs that are the best for their needs and nothing prevents them from writing this right now: ```d static if (defined(_MSC_VER) && (_MSC_VER > 600) && !defined(__INTERIX)) { static if(defined(_WIN32_WCE)) alias fdopen = (fd,mode) {}; /* No fdopen() */ else alias fdopen = _fdopen; } ``` (I took this example from [zlib](https://github.com/madler/zlib/blob/master/zutil.h#L177))
Jul 22 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/22/2022 9:24 PM, Andrey Zherikov wrote:
 Unfortunately as you know people don't care about what you discourage or 
 encourage. People just try to express their intent using those language
structs 
 that are the best for their needs and nothing prevents them from writing this 
 right now:
 
 ```d
 static if (defined(_MSC_VER) && (_MSC_VER > 600) && !defined(__INTERIX))
 {
    static if(defined(_WIN32_WCE))
       alias fdopen = (fd,mode) {}; /* No fdopen() */
    else
       alias fdopen = _fdopen;
 }
 ```
 
 (I took this example from 
 [zlib](https://github.com/madler/zlib/blob/master/zutil.h#L177))
`defined` doesn't work in D. The idea is to make the wrong way unattractive and clumsy enough that people will look for a better way, which we provide. BTW, I've been through the zlib .h files, in the course of dogfooding it with ImportC. Every ugly practice I complain about with #if's is in full display there. Here's another gem from your link: #if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) #endif It's just madness.
Jul 23 2022
parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Saturday, 23 July 2022 at 20:12:29 UTC, Walter Bright wrote:
 `defined` doesn't work in D.
Sorry, I didn't think that I had to provide fully working example to illustrate an idea ;)
 The idea is to make the wrong way unattractive and clumsy 
 enough that people will look for a better way, which we provide.

 BTW, I've been through the zlib .h files, in the course of 
 dogfooding it with ImportC. Every ugly practice I complain 
 about with #if's is in full display there.

 Here's another gem from your link:

 ```
 #if defined(STDC) && !defined(HAVE_MEMCPY) && 
 !defined(NO_MEMCPY)

 #endif
 ```

 It's just madness.
I totally understand you and your intentions with this. But I'd like to get your recommendation on the following situation. As a library developer I want to provide some SLA to the users: I guarantee that my library will be successfully built by all versions of all compilers (ldc,gdc,dmd) that are one year old or newer. The thing is that compilers evolve (they got new features, bug fixes etc) and I want my codebase evolve with them. I can easily check what compiler is used by `version(DigitalMars)` e.g.. But how should I check that a specific feature is added to compiler/phobos or a specific bug is fixed?
Jul 26 2022
next sibling parent reply "H. S. Teoh" <hsteoh qfbox.info> writes:
On Tue, Jul 26, 2022 at 10:52:29AM +0000, Andrey Zherikov via Digitalmars-d
wrote:
[...]
 As a library developer I want to provide some SLA to the users: I
 guarantee that my library will be successfully built by all versions
 of all compilers (ldc,gdc,dmd) that are one year old or newer. The
 thing is that compilers evolve (they got new features, bug fixes etc)
 and I want my codebase evolve with them. I can easily check what
 compiler is used by `version(DigitalMars)` e.g.. But how should I
 check that a specific feature is added to compiler/phobos or a
 specific bug is fixed?
static if (__VERSION__ == 2098L) { ... // 2.098-specific code } static if (__VERSION__ == 2100L) { ... // 2.100-specific code } // and so on T -- There are 10 kinds of people in the world: those who can count in binary, and those who can't.
Jul 26 2022
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/26/22 9:27 AM, H. S. Teoh wrote:
 On Tue, Jul 26, 2022 at 10:52:29AM +0000, Andrey Zherikov via Digitalmars-d
wrote:
 [...]
 As a library developer I want to provide some SLA to the users: I
 guarantee that my library will be successfully built by all versions
 of all compilers (ldc,gdc,dmd) that are one year old or newer. The
 thing is that compilers evolve (they got new features, bug fixes etc)
 and I want my codebase evolve with them. I can easily check what
 compiler is used by `version(DigitalMars)` e.g.. But how should I
 check that a specific feature is added to compiler/phobos or a
 specific bug is fixed?
static if (__VERSION__ == 2098L) { ... // 2.098-specific code } static if (__VERSION__ == 2100L) { ... // 2.100-specific code } // and so on
Ironic that DMD's provided meta doesn't feel the burden of dealing with the crippled version system. -Steve
Jul 26 2022
prev sibling parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Tuesday, 26 July 2022 at 13:27:55 UTC, H. S. Teoh wrote:
 On Tue, Jul 26, 2022 at 10:52:29AM +0000, Andrey Zherikov via 
 Digitalmars-d wrote: [...]
 As a library developer I want to provide some SLA to the 
 users: I guarantee that my library will be successfully built 
 by all versions of all compilers (ldc,gdc,dmd) that are one 
 year old or newer. The thing is that compilers evolve (they 
 got new features, bug fixes etc) and I want my codebase evolve 
 with them. I can easily check what compiler is used by 
 `version(DigitalMars)` e.g.. But how should I check that a 
 specific feature is added to compiler/phobos or a specific bug 
 is fixed?
``` static if (__VERSION__ == 2098L) { ... // 2.098-specific code } static if (__VERSION__ == 2100L) { ... // 2.100-specific code } // and so on ```
This is discouraged usage according to Walter, isn't it?
Jul 26 2022
parent reply "H. S. Teoh" <hsteoh qfbox.info> writes:
On Tue, Jul 26, 2022 at 03:19:44PM +0000, Andrey Zherikov via Digitalmars-d
wrote:
 On Tuesday, 26 July 2022 at 13:27:55 UTC, H. S. Teoh wrote:
[...]
 ```
 	static if (__VERSION__ == 2098L) {
 		... // 2.098-specific code
 	}
 	static if (__VERSION__ == 2100L) {
 		... // 2.100-specific code
 	}
 	// and so on
 ```
This is discouraged usage according to Walter, isn't it?
I guess so. :-D So maybe we need a DIP to add feature-based version identifiers, e.g.: version(fixed12345) { ... /* bug 12345 is fixed */ } version(dip1000) { ... } version(intpromote) { ... } and so on. T -- He who sacrifices functionality for ease of use, loses both and deserves neither. -- Slashdotter
Jul 26 2022
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 26 July 2022 at 17:06:17 UTC, H. S. Teoh wrote:
 [snip]

 I guess so. :-D

 So maybe we need a DIP to add feature-based version 
 identifiers, e.g.:

 	version(fixed12345) { ... /* bug 12345 is fixed */ }
 	version(dip1000) { ... }
 	version(intpromote) { ... }

 and so on.


 T
The bottom two are a bit separate. It makes perfect sense to add predefined versions for preview statements (it may even make sense to include even more than that, e.g. version statement for other D features that people may want to disable, but that's neither here nor there and a bit beyond the scope). I don't think it needs a DIP for that. Bug fixes are a bit more annoying because there are thousands of them. I would still need to look up what bug 12345 was, even though it is at least more specific than the specific a DMD version. I think checking whether the buggy code is fixed with a traits _compiles is a little more obvious.
Jul 26 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/26/2022 10:33 AM, jmh530 wrote:
 I think checking whether the buggy 
 code is fixed with a traits _compiles is a little more obvious.
And a little more obvious.
Jul 26 2022
prev sibling next sibling parent Paul Backus <snarwin gmail.com> writes:
On Tuesday, 26 July 2022 at 10:52:29 UTC, Andrey Zherikov wrote:
 But how should I check that a specific feature is added to 
 compiler/phobos or a specific bug is fixed?
You can use introspection to check for features and bug fixes directly: ```d static if (__traits(compiles, { import std.whatever: someSymbol; })) { // std.whatever.someSymbol exists } private bool hasBug() { // test case for bug } static if (hasBug) { // workaround for bug } else { // code without the workaround } ```
Jul 26 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/26/2022 3:52 AM, Andrey Zherikov wrote:
 But how should I check that a specific 
 feature is added to compiler/phobos or a specific bug is fixed?
Create a single "configuration module", which has a section for each version: -------- module config; version (DigitalMars) { import digitalmars; } else version (LDC) { import ldc; } else version (GDC) { import gdc; } else { static assert(0, "unsupported system"); } --------- Now, in digitalmars.d and ldc.d and gdc.d, do what it takes to make that configuration work for your code. This makes it really easy to concentrate, say, in ldc.d, just on ldc's characteristics. Rather than having to constantly confuse yourself with which configuration is compiling what code. It also immediately points out when the code is being built for a version you have not anticipated.
Jul 26 2022
parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 27 July 2022 at 03:42:07 UTC, Walter Bright wrote:
 On 7/26/2022 3:52 AM, Andrey Zherikov wrote:
 But how should I check that a specific feature is added to 
 compiler/phobos or a specific bug is fixed?
Create a single "configuration module", which has a section for each version: ```d module config; version (DigitalMars) { import digitalmars; } else version (LDC) { import ldc; } else version (GDC) { import gdc; } else { static assert(0, "unsupported system"); } ``` Now, in digitalmars.d and ldc.d and gdc.d, do what it takes to make that configuration work for your code. This makes it really easy to concentrate, say, in ldc.d, just on ldc's characteristics. Rather than having to constantly confuse yourself with which configuration is compiling what code.
What's your recommendation about how I should check for a specific feature/bugfix? Should I use `static if(__VERSION__ ...)`, `static if(__traits(compiles, { ... }))` or something else?
Jul 27 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/27/2022 7:24 AM, Andrey Zherikov wrote:
 What's your recommendation about how I should check for a specific 
 feature/bugfix? Should I use `static if(__VERSION__ ...)`, `static 
 if(__traits(compiles, { ... }))` or something else?
__VERSION__ is certainly more convenient. Though, since upgrades to the compiler are free, a simpler strategy would be to just require a __VERSION__ past a certain point.
Jul 27 2022
parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 27 July 2022 at 17:16:30 UTC, Walter Bright wrote:
 On 7/27/2022 7:24 AM, Andrey Zherikov wrote:
 What's your recommendation about how I should check for a 
 specific feature/bugfix? Should I use `static if(__VERSION__ 
 ...)`, `static if(__traits(compiles, { ... }))` or something 
 else?
__VERSION__ is certainly more convenient. Though, since upgrades to the compiler are free, a simpler strategy would be to just require a __VERSION__ past a certain point.
Did I get you right that you discourage using `static if` for versioning the code (according to [this post](https://forum.dlang.org/post/tbair7$2ltc$1 digitalmars.com)) with an exception for `static if(__VERSION__ ...)`?
Jul 28 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/28/2022 7:57 AM, Andrey Zherikov wrote:
 Did I get you right that you discourage using `static if` for versioning the 
 code (according to [this 
 post](https://forum.dlang.org/post/tbair7$2ltc$1 digitalmars.com)) with an 
 exception for `static if(__VERSION__ ...)`?
Yes, you did. Mainly, because the compiler doesn't generate a predefined version for every change, which is impractical. Frankly, what you're trying to do is hopeless, hence the suggestion to simply pick a minimum __VERSION__ to support.
Jul 28 2022
parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Friday, 29 July 2022 at 01:04:42 UTC, Walter Bright wrote:
 On 7/28/2022 7:57 AM, Andrey Zherikov wrote:
 Did I get you right that you discourage using `static if` for 
 versioning the code (according to [this 
 post](https://forum.dlang.org/post/tbair7$2ltc$1 digitalmars.com)) with an
exception for `static if(__VERSION__ ...)`?
Yes, you did. Mainly, because the compiler doesn't generate a predefined version for every change, which is impractical. Frankly, what you're trying to do is hopeless, hence the suggestion to simply pick a minimum __VERSION__ to support.
I'm just trying to clarify your recommendations as a language author. Whether I like it or not is different question but making things clear is important IMO. Thanks for your answers!
Jul 29 2022
prev sibling parent reply Dennis <dkorpel gmail.com> writes:
On Thursday, 21 July 2022 at 03:57:31 UTC, Walter Bright wrote:
 Yes, the numbers are a failed idea of mine. I'd endorse 
 deprecating them.
They are now deprecated: https://github.com/dlang/dmd/pull/14330
Jul 26 2022
parent Kagamin <spam here.lot> writes:
On Tuesday, 26 July 2022 at 19:25:14 UTC, Dennis wrote:
 On Thursday, 21 July 2022 at 03:57:31 UTC, Walter Bright wrote:
 Yes, the numbers are a failed idea of mine. I'd endorse 
 deprecating them.
They are now deprecated: https://github.com/dlang/dmd/pull/14330
You misquoted, and debug(number) wasn't discussed. If dependencies can't use numbers, it doesn't mean that nothing can use numbers. All version statements don't work for dependencies, because those can be compiled in a different way, which manifested for phobos in practice. In case of debug statement it can mean debugging fidelity, which is meaningful and can span dependencies, if they are compiled with the same settings.
Apr 16 2023
prev sibling next sibling parent reply jfondren <julian.fondren gmail.com> writes:
On Wednesday, 20 July 2022 at 01:22:00 UTC, Andrey Zherikov wrote:
 I actually have a question since this topic is brought up:
 What is conceptual difference between `version(FOO)` and 
 `static if(FOO)`? I see `version` is a very limited comparing 
 to `static if` - the former checks for "boolean" result 
 (whether an ID is defined) while the latter evaluates condition 
 expression.
Consider: ```d enum Test = true; void main() { import std.stdio : writeln; version(Test) { writeln("true"); } else { writeln("false"); } } ``` And this output: ``` $ dmd -run example.d false $ dmd -version=Test -run example.d true ``` A few seconds of hacking with a build system though, and static if seems to be enough: ```d import mbs = magic_buildsystem_definitions; enum Test = true; void main() { import std.stdio : writeln; static if (mbs.Test) { writeln("true"); } else { writeln("false"); } } ``` with that module generated of course by the build system, and any logic you like now capable. version's limited expressiveness is due to experience with `#ifdef` abuse in C, much like (I imagine) limitations like "the code won't even compile if you're not using an import" exists in Go. You could positively say that such limitations are lessons learned and you could negatively say that they're expressions of trauma.
Jul 19 2022
next sibling parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 20 July 2022 at 01:38:41 UTC, jfondren wrote:
 A few seconds of hacking with a build system though, and static 
 if seems to be enough:

 ```d
 import mbs = magic_buildsystem_definitions;

 enum Test = true;

 void main() {
     import std.stdio : writeln;

     static if (mbs.Test) {
         writeln("true");
     } else {
         writeln("false");
     }
 }
 ```

 with that module generated of course by the build system, and 
 any logic you like now capable.
I'd like build system to not generate any files with compile-time constants.
 version's limited expressiveness is due to experience with 
 `#ifdef` abuse in C, much like (I imagine) limitations like 
 "the code won't even compile if you're not using an import" 
 exists in Go. You could positively say that such limitations 
 are lessons learned and you could negatively say that they're 
 expressions of trauma.
I'm not sure I got what `#ifdef` issue is referenced. Is it something like the one described in https://www.usenix.org/legacy/publications/library/proceedings/sa92/spencer.pdf?
Jul 19 2022
prev sibling parent reply Hipreme <msnmancini hotmail.com> writes:
On Wednesday, 20 July 2022 at 01:38:41 UTC, jfondren wrote:
 On Wednesday, 20 July 2022 at 01:22:00 UTC, Andrey Zherikov 
 wrote:
 I actually have a question since this topic is brought up:
 What is conceptual difference between `version(FOO)` and 
 `static if(FOO)`? I see `version` is a very limited comparing 
 to `static if` - the former checks for "boolean" result 
 (whether an ID is defined) while the latter evaluates 
 condition expression.
Consider: ```d enum Test = true; void main() { import std.stdio : writeln; version(Test) { writeln("true"); } else { writeln("false"); } } ``` And this output: ``` $ dmd -run example.d false $ dmd -version=Test -run example.d true ``` A few seconds of hacking with a build system though, and static if seems to be enough: ```d import mbs = magic_buildsystem_definitions; enum Test = true; void main() { import std.stdio : writeln; static if (mbs.Test) { writeln("true"); } else { writeln("false"); } } ``` with that module generated of course by the build system, and any logic you like now capable. version's limited expressiveness is due to experience with `#ifdef` abuse in C, much like (I imagine) limitations like "the code won't even compile if you're not using an import" exists in Go. You could positively say that such limitations are lessons learned and you could negatively say that they're expressions of trauma.
It is virtually impossible to recreate the mess macros done. They were so messy because one could define AND undefine them, which made tracking a lot hard. Even worse, macros were used for everything. Constants, inline functions, templates, syntax transformers, aliases, conditional compilation, importing. D has already solved that by creating specific tool for each thing, giving a way to define version as a namespaced number would hardly make anything more complex. If you take the use case i bring for example, you you actually check it would make it easier to understand
Jul 19 2022
parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 20 July 2022 at 03:18:15 UTC, Hipreme wrote:
 It is virtually impossible to recreate the mess macros done. 
 They were so messy because one could define AND undefine them, 
 which made tracking a lot hard.
I agree, this is bad use case and I'm glad that D didn't allow it.
 Even worse, macros were used for everything. Constants, inline 
 functions, templates, syntax transformers, aliases, conditional 
 compilation, importing.

 D has already solved that by creating specific tool for each 
 thing
Right and I believe that setting compile time constants in compiler command line would benefit everyone.
 giving a way to define version as a namespaced number would 
 hardly make anything more complex. If you take the use case i 
 bring for example, you you actually check it would make it 
 easier to understand
I think that `version(V >= 5)` is not harder to understand than `version(V.5)`. But `V >= 5` clearer defines that it's true when V==6 which is not obvious with `V.5` - you need to get used to that.
Jul 19 2022
prev sibling parent reply Kagamin <spam here.lot> writes:
On Wednesday, 20 July 2022 at 01:22:00 UTC, Andrey Zherikov wrote:
 I actually have a question since this topic is brought up:
 What is conceptual difference between `version(FOO)` and 
 `static if(FOO)`?
`version` is faster, `static if` has more features.
Jul 20 2022
parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 20 July 2022 at 18:29:28 UTC, Kagamin wrote:
 On Wednesday, 20 July 2022 at 01:22:00 UTC, Andrey Zherikov 
 wrote:
 I actually have a question since this topic is brought up:
 What is conceptual difference between `version(FOO)` and 
 `static if(FOO)`?
`version` is faster
Do you have performance benchmark to share?
Jul 20 2022
next sibling parent Kagamin <spam here.lot> writes:
On Wednesday, 20 July 2022 at 18:34:49 UTC, Andrey Zherikov wrote:
 On Wednesday, 20 July 2022 at 18:29:28 UTC, Kagamin wrote:
 On Wednesday, 20 July 2022 at 01:22:00 UTC, Andrey Zherikov 
 wrote:
 I actually have a question since this topic is brought up:
 What is conceptual difference between `version(FOO)` and 
 `static if(FOO)`?
`version` is faster
Do you have performance benchmark to share?
`static if` can evaluate arbitrarily complex code, it has no upper complexity bound.
Jul 21 2022
prev sibling parent Kagamin <spam here.lot> writes:
On Wednesday, 20 July 2022 at 18:34:49 UTC, Andrey Zherikov wrote:
 Do you have performance benchmark to share?
Feel free to benchmark this: ``` bool run(int seed) { int a=seed, b=10; while(a!=0) { a+=b; b^=a<<8; b+=a; a^=b>>8; if(b==0)return true; } return false; } static if(run(2)); ```
Jul 21 2022
prev sibling next sibling parent reply apz28 <home home.com> writes:
On Tuesday, 19 July 2022 at 22:30:28 UTC, Hipreme wrote:
 version(number) actually contains something really nice on it. 
 But it is useless.

 For example: version(3) would actually declare version(2) and 
 version(1).

 The problem is that these doesn't mean anything at all, but 
 they have this property of waterfall. Which is totally missing 
 in D right now. Take this as an example:

 ```d

 version(V1_3)
     version = V1_2;
 version(V1_2)
     version = V1_1;
 version(V1_1)
     version = V1_0;
 ```
D Version is very limit. It should expand to include the version number version(string-part.float-part) ex: version = foo.1.3 string-part = foo float-part = 1.3 true usage = version(foo >= 1) {with version check} version(foo) {without version check} false usage version(foo >= 2) {never compiled block} ex: version = foo string-part = foo float-part = 0.0 Anyway, "static if" construct is not same as version https://issues.dlang.org/show_bug.cgi?id=16666
Jul 20 2022
parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 20 July 2022 at 17:55:20 UTC, apz28 wrote:
 Anyway, "static if" construct is not same as version
 https://issues.dlang.org/show_bug.cgi?id=16666
I don't thins that this is good example. The bug is actually about that `static if` doesn't work with forward declaration: ```d void func(S s) {} version (WORKING) struct S {} else static if (true) struct S {} ``` This fails with `Error: undefined identifier 'S'` and passes with `dmd -version=WORKING`. Anyway this can be fixed.
Jul 20 2022
parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 20 July 2022 at 18:33:50 UTC, Andrey Zherikov wrote:
 On Wednesday, 20 July 2022 at 17:55:20 UTC, apz28 wrote:
 Anyway, "static if" construct is not same as version
 https://issues.dlang.org/show_bug.cgi?id=16666
I don't thins that this is good example. The bug is actually about that `static if` doesn't work with forward declaration: ```d void func(S s) {} version (WORKING) struct S {} else static if (true) struct S {} ``` This fails with `Error: undefined identifier 'S'` and passes with `dmd -version=WORKING`. Anyway this can be fixed.
The interesting thing is that only top-level `static if` fails. This works: ```d void func(A.S s) {} struct A { version (WORKING) struct S {} else static if (true) struct S {} } ```
Jul 20 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/19/2022 3:30 PM, Hipreme wrote:
 version(V1_3)
      version = V1_2;
 version(V1_2)
      version = V1_1;
 version(V1_1)
      version = V1_0;
This kind of thing is indeed terrible. Fortunately, there are better ways. Let's say you've got FeatureX, and it exists in some versions and not in others. Worse way: version (X) doX(); Better way: import X; doX(); Inside module X: module X; version (X) void X() { ... } else void X() {} Now, let's say version Y and Z both rely on X being implemented: import X; doX(); module X: version (Y) import Ximpl : X; else version (Z) import Ximpl : Y; else void X() { } module Ximpl: module Ximpl; void X() { ... } Essentially, what you wind up with is, for each of the versions, there will be a straightforward list of which features are implemented for it. These manifests only appear once in your code, and are easy to maintain. The complaint about this comes from the DRY principle, people do not want to duplicate a single line of code (in this case, the import lines). But once one gets past DRY, the readability of each version having its own list begins to look much more attractive. Even better, when one adds a new version, the addition becomes straightforward rather than weaving it into a tangle of other conditional compilation sections. I know you're not convinced. But I ask that you think about it, and give it a try. I bet you like the results. And you won't have that conditional compilation mess *per file* anymore.
Jul 20 2022
parent reply Hipreme <msnmancini hotmail.com> writes:
On Thursday, 21 July 2022 at 04:11:57 UTC, Walter Bright wrote:
 On 7/19/2022 3:30 PM, Hipreme wrote:
 version(V1_3)
      version = V1_2;
 version(V1_2)
      version = V1_1;
 version(V1_1)
      version = V1_0;
This kind of thing is indeed terrible. Fortunately, there are better ways. Let's say you've got FeatureX, and it exists in some versions and not in others. Worse way: version (X) doX(); Better way: import X; doX(); Inside module X: module X; version (X) void X() { ... } else void X() {} Now, let's say version Y and Z both rely on X being implemented: import X; doX(); module X: version (Y) import Ximpl : X; else version (Z) import Ximpl : Y; else void X() { } module Ximpl: module Ximpl; void X() { ... } Essentially, what you wind up with is, for each of the versions, there will be a straightforward list of which features are implemented for it. These manifests only appear once in your code, and are easy to maintain. The complaint about this comes from the DRY principle, people do not want to duplicate a single line of code (in this case, the import lines). But once one gets past DRY, the readability of each version having its own list begins to look much more attractive. Even better, when one adds a new version, the addition becomes straightforward rather than weaving it into a tangle of other conditional compilation sections. I know you're not convinced. But I ask that you think about it, and give it a try. I bet you like the results. And you won't have that conditional compilation mess *per file* anymore.
Okay, so what I asked is not exactly doing as people here thought like: ```d version(SDL > 2) ``` What I asked is basically, for maintaining the same behaviour we have right now, when defining like SDL.2.5, it would define: ```d version(SDL.2.5) //Ok version(SDL.2.4) //Ok version(SDL.2.3) //Ok version(SDL.2.2) //Ok version(SDL.2.1) //Ok version(SDL.2.0) //Ok version(SDL.1.9) //Not ok ``` It would basically just insert all possible versions when defining with a number like that, I'm not expecting to use those kind of operators with `version`. I have discussed and many people agree that doing many logical operators (besides `!version` (I do a lot of version(){}else{}) ) is bad.
Jul 22 2022
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Friday, 22 July 2022 at 10:36:39 UTC, Hipreme wrote:

 ```d
 version(SDL.2.5) //Ok
 version(SDL.2.4) //Ok
 version(SDL.2.3) //Ok
 version(SDL.2.2) //Ok
 version(SDL.2.1) //Ok
 version(SDL.2.0) //Ok
 version(SDL.1.9) //Not ok
 ```

 It would basically just insert all possible versions when 
 defining with a number like that, I'm not expecting to use 
 those kind of operators with `version`. I
Then what happens when you *don't* want old versions together with the new one?
Jul 22 2022
parent reply Hipreme <msnmancini hotmail.com> writes:
On Friday, 22 July 2022 at 10:43:03 UTC, Mike Parker wrote:
 On Friday, 22 July 2022 at 10:36:39 UTC, Hipreme wrote:

 ```d
 version(SDL.2.5) //Ok
 version(SDL.2.4) //Ok
 version(SDL.2.3) //Ok
 version(SDL.2.2) //Ok
 version(SDL.2.1) //Ok
 version(SDL.2.0) //Ok
 version(SDL.1.9) //Not ok
 ```

 It would basically just insert all possible versions when 
 defining with a number like that, I'm not expecting to use 
 those kind of operators with `version`. I
Then what happens when you *don't* want old versions together with the new one?
I'm thinking about newer versions with incremental additions. When I was looking into directx-d bindings, most of newer version depends on older version unless they change its major. The same thing could be applied to: ```d version(SDL.2.5.5) ... version(SDL.2.5.0) //Ok version(SDL.2.4) //not ok ```
Jul 22 2022
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Friday, 22 July 2022 at 13:36:37 UTC, Hipreme wrote:

 I'm thinking about newer versions with incremental additions.
 When I was looking into directx-d bindings, most of newer 
 version depends on older version unless they change its major. 
 The same thing could be applied to:

 ```d
 version(SDL.2.5.5)
 ...
 version(SDL.2.5.0) //Ok
 version(SDL.2.4) //not ok
 ```
And then you're baking a library versioning scheme into the language. Not sure about that.
Jul 22 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/22/2022 6:36 AM, Hipreme wrote:
 version(SDL.2.5.5)
 ...
 version(SDL.2.5.0) //Ok
 version(SDL.2.4) //not ok
The reader has no idea what actual feature is being turned on or off.
Jul 22 2022
parent reply Hipreme <msnmancini hotmail.com> writes:
On Friday, 22 July 2022 at 18:22:52 UTC, Walter Bright wrote:
 On 7/22/2022 6:36 AM, Hipreme wrote:
 version(SDL.2.5.5)
 ...
 version(SDL.2.5.0) //Ok
 version(SDL.2.4) //not ok
The reader has no idea what actual feature is being turned on or off.
I understand your point. But there exists a problem. The reason why version was been created seems basically: ```d version(FeatureA){} version(FeatureB){} ``` Trying to use numbers on version doesn't seem to be what you have planned. I believe the naming could be `feature(A)` instead of version because it would make a lot more sense. In my case, I have been coding a game engine which you can turn off or on a lot of features like: `version(JSONParsing)` `version(XMLParsing)`, which it is easy to understand exactly what is happening, but it actually does not really reflect what a version is. But, how one would approach when the feature is version dependent? This becomes a lot harder to reason about, the version number could mean anything. Specially approaching bindings, which other languages already has that convention of making/not making available functions based on version, it becomes even harder when this function can be enabled/disabled and is even build version dependent
Jul 22 2022
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Saturday, 23 July 2022 at 00:33:36 UTC, Hipreme wrote:

 Trying to use numbers on version doesn't seem to be what you 
 have planned.
 I believe the naming could be `feature(A)` instead of version 
 because it would make a lot more sense. In my case, I have been 
 coding a game engine which you can turn off or on a lot of 
 features like: `version(JSONParsing)` `version(XMLParsing)`, 
 which it is easy to understand exactly what is happening, but 
 it actually does not really reflect what a version is.
What is a version? Linux version, Windows version, free version, licensed version, alpha version, beta version, gold version... `version` is about more than just individual features and is broader than "project version number".
 But, how one would approach when the feature is version 
 dependent? This becomes a lot harder to reason about, the 
 version number could mean anything.
You can use the approach I already recommended with static if and enums. Then you get to define exactly what a version number represents (e.g., only features from 2.5.2 or all features from 2.x). I know Walter doesn't like it, but it works great. You can also use your build system to set up specific configurations of version combinations.
 Specially approaching bindings, which other languages already 
 has that convention of making/not making available functions 
 based on version, it becomes even harder when this function can 
 be enabled/disabled and is even build version dependent
Consider again my bindbc bindings. SDL remains backwards compatible on ever minor version, so the API of 2.5 is still available in 2.10. Then there's Lua, which removes or renames C API functions in almost every minor release. Static if + enums allows me to handle both cases with `version(SDL_NNNN)` and `version(LUA_NNNN)`. `version` is very simple and easy to understand. Why would you want to add complexity to it when you can already do what you want to do?
Jul 22 2022
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/22/2022 5:33 PM, Hipreme wrote:
 But, how one would approach when the feature is version dependent? This
becomes 
 a lot harder to reason about, the version number could mean anything.
Specially 
 approaching bindings, which other languages already has that convention of 
 making/not making available functions based on version, it becomes even harder 
 when this function can be enabled/disabled and is even build version dependent
New versions are not just numbers. They are an arbitrary collection of new features and modified features. Nobody, not even the author, will remember which feature goes with which version number. My recommendation is to use version identifiers for each of those features that changed that matter to your program. It's rarely more than a handful. It'll make your code a pleasure to read, too.
Jul 22 2022
prev sibling parent reply "H. S. Teoh" <hsteoh qfbox.info> writes:
On Sat, Jul 23, 2022 at 12:33:36AM +0000, Hipreme via Digitalmars-d wrote:
 On Friday, 22 July 2022 at 18:22:52 UTC, Walter Bright wrote:
 On 7/22/2022 6:36 AM, Hipreme wrote:
 version(SDL.2.5.5)
 ...
 version(SDL.2.5.0) //Ok
 version(SDL.2.4) //not ok
The reader has no idea what actual feature is being turned on or off.
I understand your point. But there exists a problem. The reason why version was been created seems basically: ```d version(FeatureA){} version(FeatureB){} ``` Trying to use numbers on version doesn't seem to be what you have planned. I believe the naming could be `feature(A)` instead of version because it would make a lot more sense. In my case, I have been coding a game engine which you can turn off or on a lot of features like: `version(JSONParsing)` `version(XMLParsing)`, which it is easy to understand exactly what is happening, but it actually does not really reflect what a version is. But, how one would approach when the feature is version dependent? This becomes a lot harder to reason about, the version number could mean anything. Specially approaching bindings, which other languages already has that convention of making/not making available functions based on version, it becomes even harder when this function can be enabled/disabled and is even build version dependent
[...] Maybe something like this? version(build1234) { version = FeatureA; version = FeatureB; // etc. } version(build1235) { version = FeatureA; version = FeatureC; // etc. } ... version(FeatureA) { ... /* feature A implementation here */ } version(FeatureB) { ... /* feature B implementation here */ } // etc. T -- What's an anagram of "BANACH-TARSKI"? BANACH-TARSKI BANACH-TARSKI.
Jul 22 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/22/2022 8:06 PM, H. S. Teoh wrote:
 Maybe something like this?
 
 	version(build1234) {
 		version = FeatureA;
 		version = FeatureB;
 		// etc.
 	}
 
 	version(build1235) {
 		version = FeatureA;
 		version = FeatureC;
 		// etc.
 	}
 
 	...
 
 	version(FeatureA) { ... /* feature A implementation here */ }
 	version(FeatureB) { ... /* feature B implementation here */ }
 	// etc.
Awkward since you cannot import versions from other modules.
Jul 23 2022
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 24/07/2022 7:53 AM, Walter Bright wrote:
 Awkward since you cannot import versions from other modules.
Perhaps we should be changing that. It does seem to be a unnecessary limitation given that an enum can be used in its place.
Jul 23 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/23/2022 1:08 PM, rikki cattermole wrote:
 
 On 24/07/2022 7:53 AM, Walter Bright wrote:
 Awkward since you cannot import versions from other modules.
Perhaps we should be changing that.
1. then you can't tell which versions are active 2. circular imports become hell
 It does seem to be a unnecessary limitation given that an enum can be used in 
 its place.
Yes, and when that was done in druntime it produced baffling issues because of circular imports. The problems got dumped in my lap. I yanked it all out and did it right. No problems since.
Jul 23 2022
parent Max Samukha <maxsamukha gmail.com> writes:
On Sunday, 24 July 2022 at 02:24:39 UTC, Walter Bright wrote:

 Yes, and when that was done in druntime it produced baffling 
 issues because of circular imports. The problems got dumped in 
 my lap. I yanked it all out and did it right. No problems since.
Choosing a different set of problems never results in no problems.
Jul 24 2022
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/22/2022 3:36 AM, Hipreme wrote:
 Okay, so what I asked is not exactly doing as people here thought like:
 ```d
 version(SDL > 2)
 ```
 
 
 What I asked is basically, for maintaining the same behaviour we have right
now, 
 when defining like SDL.2.5, it would define:
 
 ```d
 version(SDL.2.5) //Ok
 version(SDL.2.4) //Ok
 version(SDL.2.3) //Ok
 version(SDL.2.2) //Ok
 version(SDL.2.1) //Ok
 version(SDL.2.0) //Ok
 version(SDL.1.9) //Not ok
 ```
 
 It would basically just insert all possible versions when defining with a
number 
 like that, I'm not expecting to use those kind of operators with `version`.
I know, this is an 'OR' operation. My proposal is a better way of doing this.
 I have discussed and many people agree that doing many logical operators
(besides 
 `!version` (I do a lot of version(){}else{}) ) is bad.
!version is something I try to destroy. Versions should be positive affirmations, not negative ones. For example, version(DEMO) ... do demo stuff... !version(DEMO) ... do release stuff ... Better is to have `version(RELEASE)`. Even better, version the feature itself that you're turning on. Rationale: I've seen endless `#if CompilerVersion > 6` in C with all kinds of versions, and the poor reader has no idea what features are being turned on and off with them.
Jul 22 2022