Thread overview | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
July 28, 2012 FYI my experience with D' version | ||||
---|---|---|---|---|
| ||||
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. |
July 29, 2012 Re: FYI my experience with D' version | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | I just hit another downside with custom version(): two libraries might use the same name to mean different things. The version has no namespacing, so that's another reason for not using it for custom things. The config modules might be the best idea for libraries too. I wonder if we could do a default module that is easily overridden.... |
July 29, 2012 Re: FYI my experience with D' version | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On 2012-07-29 18:42, Adam D. Ruppe wrote: > I just hit another downside with custom version(): two libraries > might use the same name to mean different things. > > The version has no namespacing, so that's another reason for not > using it for custom things. The config modules might be the best idea > for libraries too. I wonder if we could do a default module that is > easily overridden.... You could use versions which sets bool variables and use static-if. I don't know if that's any better. -- /Jacob Carlborg |
July 30, 2012 Re: FYI my experience with D' version | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe |
> 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.
Couldn't you make a template mixin that inserts default values if not yet defined?
|
July 30, 2012 Re: FYI my experience with D' version | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On 28.07.2012 22:55, Adam D. Ruppe wrote:
> 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 }
version is good for global options that you set with -version on the command line. And can also be used internally in a module, but doesn't work across modules. But it seems you have discovered this the hard way already.
I think there was a discussion about this a few years ago, Walter did it this way on purpose. Can't remember the details, though.
|
July 30, 2012 Re: FYI my experience with D' version | ||||
---|---|---|---|---|
| ||||
Posted in reply to torhu | On 2012-07-30 12:30, torhu wrote: > version is good for global options that you set with -version on the > command line. And can also be used internally in a module, but doesn't > work across modules. But it seems you have discovered this the hard way > already. > > I think there was a discussion about this a few years ago, Walter did it > this way on purpose. Can't remember the details, though. He probably wants to avoid the C macro hell. -- /Jacob Carlborg |
July 30, 2012 Re: FYI my experience with D' version | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On 30/07/12 14:32, Jacob Carlborg wrote:
> On 2012-07-30 12:30, torhu wrote:
>
>> version is good for global options that you set with -version on the
>> command line. And can also be used internally in a module, but doesn't
>> work across modules. But it seems you have discovered this the hard way
>> already.
>>
>> I think there was a discussion about this a few years ago, Walter did it
>> this way on purpose. Can't remember the details, though.
>
> He probably wants to avoid the C macro hell.
>
IIRC it's because version identifiers are global.
______________________________
module b;
version = CoolStuff;
______________________________
module a;
import b;
version (X86)
{
version = CoolStuff;
}
version(CoolStuff)
{
// Looks as though this is only true on X86.
// But because module b used the same name, it's actually true always.
}
______________________________
These types of problems would be avoided if we used the one-definition rule for version statements, bugzilla 7417.
|
July 30, 2012 Re: FYI my experience with D' version | ||||
---|---|---|---|---|
| ||||
Posted in reply to torhu | On Monday, 30 July 2012 at 10:30:12 UTC, torhu wrote:
> I think there was a discussion about this a few years ago, Walter did it this way on purpose. Can't remember the details, though.
Hell, that might have been me. I first realized version doesn't
work for what I was using it for a couple years back.
Since then, I've been trying to nail down what it is good
for and alternatives for the config stuff I used to use it
for.
This thread is basically me sharing what I've learned so far.
|
July 30, 2012 Re: FYI my experience with D' version | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Sunday, 29 July 2012 at 19:20:30 UTC, Jacob Carlborg wrote:
> You could use versions which sets bool variables and use static-if. I don't know if that's any better.
It'd still have the problem of the global name. Consider:
-version=use_foo
but then lib a and lib b both have:
version(use_foo)
bool usingFoo = true;
but they have different meanings of what "foo" mean. The
bool there won't trample cross module, but the version will
still set it inappropriately.
I really think using version() for features is just always
a mistake since these things do happen anyway. The only place
where it is clear is things like platform versions.
|
Copyright © 1999-2021 by the D Language Foundation