Good examples of version() algebra in real code
Hipreme
msnmancini at hotmail.com
Mon May 22 11:06:33 UTC 2023
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).
More information about the Digitalmars-d
mailing list