digitalmars.D - Does D allow paradoxical code?
- Jerry Quinn (16/16) Mar 25 2010 What should happen when the following code is compiled?
- BCS (7/10) Mar 25 2010 I think (but am not sure) that this is an inevitable side effect of D be...
- Nick Sabalausky (15/39) Mar 25 2010 It's useful in robotics:
- Daniel Keep (19/41) Mar 25 2010 The D spec, as far as I know, says nothing on this. Then again, the D
- Jerry Quinn (6/27) Mar 27 2010 That's why I'm bringing this issue up. The spec needs to become the rel...
- Rainer Schuetze (28/50) Mar 27 2010 With the patch in bugzilla #461 (
What should happen when the following code is compiled? mixin(vs); version(v1) { const string vs = "version = v2;"; pragma(msg, "yes"); } else { const string vs = "version = v1;"; pragma(msg, "no"); } Currently, there's an error saying that vs must be a string. However, as far as I can tell, the spec says nothing about order affecting module-scope declarations. So vs should be valid, and once it substitutes in the mixin, you have a cycle where no matter what vs is, vs should be the other value. If you don't have the conditional compilation and put the declaration of vs after the mixin, it works as expected. This generally raises the question of what should be the order of evaluation for constructs like mixins, conditional compilation, and CTFE. Each has the potential to modify the other. What should be the rule to break the ambiguity? Or do we leave it implementation-defined? Thoughts? Jerry
Mar 25 2010
Hello Jerry,once it substitutes in the mixin, you have a cycle where no matter what vs is, vs should be the other value.I think (but am not sure) that this is an inevitable side effect of D being Turing compleat at compile time. As a corollary, there is no way to enforce a rule against it. I'd say it's invalid but the compiler need not detect it in any or all cases. -- ... <IXOYE><
Mar 25 2010
"Jerry Quinn" <jlquinn optonline.net> wrote in message news:hohgnr$2333$1 digitalmars.com...What should happen when the following code is compiled? mixin(vs); version(v1) { const string vs = "version = v2;"; pragma(msg, "yes"); } else { const string vs = "version = v1;"; pragma(msg, "no"); } Currently, there's an error saying that vs must be a string. However, as far as I can tell, the spec says nothing about order affecting module-scope declarations. So vs should be valid, and once it substitutes in the mixin, you have a cycle where no matter what vs is, vs should be the other value. If you don't have the conditional compilation and put the declaration of vs after the mixin, it works as expected. This generally raises the question of what should be the order of evaluation for constructs like mixins, conditional compilation, and CTFE. Each has the potential to modify the other. What should be the rule to break the ambiguity? Or do we leave it implementation-defined? Thoughts? JerryIt's useful in robotics: void blowUp() { mixin(vs); version(v1) { const string vs = "version = v2;"; pragma(msg, "yes"); } else { const string vs = "version = v1;"; pragma(msg, "no"); } }
Mar 25 2010
Jerry Quinn wrote:What should happen when the following code is compiled? mixin(vs); version(v1) { const string vs = "version = v2;"; pragma(msg, "yes"); } else { const string vs = "version = v1;"; pragma(msg, "no"); } Currently, there's an error saying that vs must be a string. However, as far as I can tell, the spec says nothing about order affecting module-scope declarations. So vs should be valid, and once it substitutes in the mixin, you have a cycle where no matter what vs is, vs should be the other value. If you don't have the conditional compilation and put the declaration of vs after the mixin, it works as expected. This generally raises the question of what should be the order of evaluation for constructs like mixins, conditional compilation, and CTFE. Each has the potential to modify the other. What should be the rule to break the ambiguity? Or do we leave it implementation-defined? Thoughts? JerryThe D spec, as far as I know, says nothing on this. Then again, the D spec says nothing about a lot of things it should. Personally, I just ignore the spec; DMD is the only reliable reference for the language. Now, being as I'm supposed to go off and do my walk around the block now, I'll be lazy and start making educated guesses. I don't think the DMD frontend is smart enough to handle this; nor do I think it should. If you were to allow this sort of thing, you'd never be able to bloody well compile it. The simplest solution is to simply make canonical what I think DMD already does: static code [1] can be arranged in any order [2], but meta code [3] is processed strictly in lexical order. Indeed, version actually already does this: you're not allowed to set a version after you've already used it. [1] being code which doesn't contain any meta code. [2] this statement, of course, this is complete garbage; work with enums for any length of time and you'll quickly discover "D supports forward references" is a dream at best. [3] being anything which generates static code; static if, foreach over a tuple, templates, mixins, etc.
Mar 25 2010
Daniel Keep Wrote:That's why I'm bringing this issue up. The spec needs to become the reliable reference rather than the DMD implementation. Otherwise, D will be difficult to use seriously because you'll never know exactly what the language really allows.This generally raises the question of what should be the order of evaluation for constructs like mixins, conditional compilation, and CTFE. Each has the potential to modify the other. What should be the rule to break the ambiguity? Or do we leave it implementation-defined? Thoughts? JerryThe D spec, as far as I know, says nothing on this. Then again, the D spec says nothing about a lot of things it should. Personally, I just ignore the spec; DMD is the only reliable reference for the language.Now, being as I'm supposed to go off and do my walk around the block now, I'll be lazy and start making educated guesses. I don't think the DMD frontend is smart enough to handle this; nor do I think it should. If you were to allow this sort of thing, you'd never be able to bloody well compile it. The simplest solution is to simply make canonical what I think DMD already does: static code [1] can be arranged in any order [2], but meta code [3] is processed strictly in lexical order. Indeed, version actually already does this: you're not allowed to set a version after you've already used it.I agree with you that this is a bit silly and I'm not looking to have the compiler "properly" run forever. I'm raising the issue to get the spec to be firmer about how these meta constructs get evaluated at compile time. Lexical order makes sense to me. Another variant of the problem I described is if you were to mixin a protection attribute where the attribute makes the string that builds it no longer visible. Jerry
Mar 27 2010
http://d.puremagic.com/issues/show_bug.cgi?id=461 ) applied, you get the expected output: test.d(1): Error: version v1 defined after use no version and debug conditions are analyzed and expanded before any other semantic analysis in a module. I think, versions are defined and limited enough, so you get what you can expect. But your point holds, if you replace version in your example with static if conditions. These need semantic analysis and this is done (mostly) in lexical order. A forward reference to an identifier defined inside the static if fails, because the identifiers inside a static if are only known in the given scope after evaluating the condition. There are also entries to that effect in bugzilla (e.g. http://d.puremagic.com/issues/show_bug.cgi?id=3743 ) Even worse, declarations inside a static if can change an overload-set, so you might not get an error, but unexpected calls that are very hard to track down. Similar problems can occur with mixins. I'm not sure CTFE falls into the same category, as it does not generate declarations by itself, it helps evaluating conditions or strings for mixins. Here's my current guess, how to allow forward references in most cases: when the compiler "visits" a scope (module, class, etc.) due to normal semantic analysis or identifier lookup, compile-time conditions and mixins at the same nesting-level must be evaluated *before anything else* in this scope. A static if condition or mixin must not reference an identifier declared inside a condition or mixin later. Rainer Jerry Quinn wrote:What should happen when the following code is compiled? mixin(vs); version(v1) { const string vs = "version = v2;"; pragma(msg, "yes"); } else { const string vs = "version = v1;"; pragma(msg, "no"); } Currently, there's an error saying that vs must be a string. However, as far as I can tell, the spec says nothing about order affecting module-scope declarations. So vs should be valid, and once it substitutes in the mixin, you have a cycle where no matter what vs is, vs should be the other value. If you don't have the conditional compilation and put the declaration of vs after the mixin, it works as expected. This generally raises the question of what should be the order of evaluation for constructs like mixins, conditional compilation, and CTFE. Each has the potential to modify the other. What should be the rule to break the ambiguity? Or do we leave it implementation-defined? Thoughts? Jerry
Mar 27 2010