digitalmars.D.learn - FYI my experience with D' version
- Adam D. Ruppe (69/69) Jul 28 2012 After some experience, I've come to the conclusion that
- Adam D. Ruppe (8/8) Jul 29 2012 I just hit another downside with custom version(): two libraries
- Jacob Carlborg (5/11) Jul 29 2012 You could use versions which sets bool variables and use static-if. I
- Adam D. Ruppe (12/14) Jul 30 2012 It'd still have the problem of the global name. Consider:
- Tobias Pankrath (2/12) Jul 30 2012 Couldn't you make a template mixin that inserts default values if
- torhu (7/23) Jul 30 2012 version is good for global options that you set with -version on the
- Jacob Carlborg (4/10) Jul 30 2012 He probably wants to avoid the C macro hell.
- Don Clugston (20/29) Jul 30 2012 IIRC it's because version identifiers are global.
- Adam D. Ruppe (7/10) Jul 30 2012 Hell, that might have been me. I first realized version doesn't
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.
Jul 28 2012
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....
Jul 29 2012
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
Jul 29 2012
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.
Jul 30 2012
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?
Jul 30 2012
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.
Jul 30 2012
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
Jul 30 2012
On 30/07/12 14:32, Jacob Carlborg wrote:On 2012-07-30 12:30, torhu wrote: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.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.
Jul 30 2012
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.
Jul 30 2012