| |
| Posted by Hipreme in reply to Walter Bright | PermalinkReply |
|
Hipreme
Posted in reply to Walter Bright
| 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).
|