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?
Jerry
It'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?
Jerry
The 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









BCS <none anon.com> 