FYI my experience with D' version

Adam D. Ruppe destructionator at gmail.com
Sat Jul 28 13:55:17 PDT 2012


After some experience, I've come to the conclusion that
using D's version() with custom things is usually a mistake.
Not always - I think it is still good for platform like tweaks,
version(X86) or version(Windows), or even version(Custom_Library),
(note, it is often smart to put an "else static assert(0)" at the
end of platform version lists, so it doesn't pass silently on new 
one)

But using it to enable or disable particular named features or
other kind of custom configuration things is a mistake. Every
time I've done it for that, I've gone back and changed it.


The reason is it is too easy to get it wrong:

module a:
version = Foo;

module b:
import a;
version(Foo) { this doesn't actually execute }


You intuitively think it would work, but it doesn't,
and it isn't an error either, so you might not notice
until you have a live bug. (This has happened to me more
than once!)



So, the question is: how do we do this kind of thing? The
solution I like best right now is to use config modules and
static if with enums. version() itself is rarely seen.

We can take advantage of the fact that D modules don't have
to match the filename to make a manageable build process:


acme_config.d
---
module application.config;

enum name = "Acme Corp.";
enum bool wantsFeatureX = false;
---

dm_config.d
---
module application.config;

enum name = "Digital Mars";
enum bool wantsFeatureX = true;
---


app.d
---
module application.app;

import application.config;

void main() {
    import std.stdio;
    writeln("Hello, ", name);
    static if(wantsFeatureX)
       writeln("You have purchased feature X!");
}
---



Now, when building the app, you just change the filename
listed for the config.

Make Acme's binary:

dmd app.d acme_config.d

Make the other one:

dmd app.d dm_config.d



and it works. Benefits include:


* All the config is centralized in a file

* The config is completely isolated from the app itself; if Acme 
buys a source license, they won't see any version(digitalmars) 
crap sprinkled about.

* Compile errors if you mess up a condition's name

* Can also be used for other customizations, including the 
company name here, but also things like defining a class to 
override some methods.



The biggest downside is if you add a function, you have to go back
to ALL the config files and add it in to make the project compile.

enum bool wantsNewFeature = false;

which can be a hassle if you have like 20 config files. But, this
is good and bad because it does make you think about it at least,
not just silently doing the wrong thing if you forget.


More information about the Digitalmars-d-learn mailing list