The D2 docs state about pragma(msg, ...): Prints a message while compiling, the AssignExpressions must be string literals: pragma(msg, "compiling..."); I think that means it must accept string literals only, and produce a syntax error in all the other cases. In practice if you look at the following program the pragma(msg, foo0()); prints the "this is a test" string. This is useful, but in many other cases this doesn't work or works in strange ways: string foo0() { return "this is a test"; } string foo1() { return ""; } string foo2() { string result; return result; } string foo3() { return []; } pragma(msg, foo0()); pragma(msg, foo1()); pragma(msg, foo2()); pragma(msg, foo3()); string hello = "red"; pragma(msg, hello); pragma(msg, 12); void main() {} The compile-timeoutput of that program is: this is a test null [] hello 12 So I think pragma(msg,...) needs some debugging. ------------- This program doesn't compile: enum int x = 10; static if (x) pragma(msg, "true"); else pragma(msg, "false"); void main() {} It prints the error: test.d(4): Declaration expected, not 'else' I can understand the cause of that error, but to improve the usefulness of the pragma and avoid errors like that one I think the compiler can rewrite the pragma(msg, ...) as: {pragma(msg, ...);} ------------- To increase the usefulness of the pragma(msg, ...) I suggest to not let it print a newline after the string. ------------- D2 programs have a better and better CTFE, so the need for good enough printing is growing. So I suggest to add a simple printing function that works in the same way both at compile-time in CTFE and at runtime. To keep things simple it can just print a string (literal or inside a variable) and it does NOT print a newline. It can be used in a loop too, in CTFE too, to print many things (so it's different from a pragma(msg,...): string foo(int i) { foreach (i, 0 .. 10) ctputs(ToString!(i)); } Note that it's a true function, so there is no need for {}. "ctputs" is just one of the possible names of this function. Once such function is present, the pragma(msg,...) can probably be removed from the language.
In D1 there were no template constraints, so to test the template arguments I used to add some static asserts inside them. So a wrong template argument shows a error message written by me that explains why the instantiation has failed (unfortunately those error messages show the line number inside the template). When a template constraint is composed of some different parts in &&, it's less easy to understand what condition has failed, so I miss the error messages written by me. This is an example (that probably I will simplify), there are four conditions, and for a person that has not written this code, and is just using Phobos, it's not immediately obvious what part has failed: auto opBinary(string op, TOther)(TOther other) if (op == "~" && is(TOther == struct) && (!__traits(compiles, { void isTuple(U...)(Tuple!U){} isTuple(other); }) || distinctFieldNames!(T, TOther.TypesAndStrings)() )) { ... There is a simple solution. The simple template constraints often don't need extra error messages, so they can be left as they are now. Putting one or more error message inside a template constraints turns them into messy code, so in such cases it's better to move the tests elsewhere, in an external template/CTFE: template IsGoodFoo(T) { static if (...) { enum bool IsGoodFoo = true; } else { ctputs("this is an error message"); return false; } } void foo(T)(T x) if (IsGoodFoo!T) { ... So the ctputs() is usable for the template constraints error messages too.
Andrei has asked if just a pragma(msg) is enough for the error template constraints. In some situations it works. But to use pragma(msg) you have to guard it with a static if. So if the template constraint is a CTFE (that uses a normal 'if' instead of a 'static if') you can't use it. While ctputs() can be used, this shows the error message even if it's not required: bool isGoodFoo(int x) { if (x > 10) { return true; } else { pragma(msg, "no good"); // ctputs("no good"); return false; } } void foo(int N)() if (isGoodFoo(N)) { } void main() { foo!(20)(); }
What about this case: auto Fn(T...)(T t) { foreach(Te; T) // compile time foreach { pragam(msg, "processing: " ~ Te.stringof) ... ctfe valid code } } void main() { Fn!(int, int, float)(1,2,3.14); // will be evaluated at _run time_ } // expected CT output: processing: int processing: int processing: float // expected runtime output: none
I don't understand what you exactly mean, but similar problems can be solved by: if (__ctfe) ctputs("..."); Or: if (!__ctfe) ctputs("...");
See also the discussion here: https://github.com/D-Programming-Language/dmd/pull/237
I don't have a github account so I'll comment here: There is use for ways to create output at runtime, CTFE time and static expansion time. For instance this function: int TemplateCTFE(T...)(int j) { for (int i = 0; i < j; i++) { foreach(t; T) { pragma(msg, t.stringof); } } } When called like this from a CTFE context: TemplateCTFE!(int, char, float)(5); will only print "int\nchar\float" once rather than 5 times. IMHO this static-expansion-time ouput is more valuable than a CTFE time output (that would output 15 line from that call). OTOH, having both would be really nice.
(In reply to comment #6) > OTOH, having both would be really nice. There are no plans to remove pragma(msg) :-)
DMD pull #692. https://github.com/D-Programming-Language/dmd/pull/692
Commits pushed to master at https://github.com/D-Programming-Language/druntime https://github.com/D-Programming-Language/druntime/commit/52494246e8f7ac08c3f5f40d379ced763e8103e3 fix Issue 3952 part 4: Add __ctfeWrite and __ctfeWriteln. This is the druntime part of the fix. https://github.com/D-Programming-Language/druntime/commit/58afd8b349567873777387119dc36a9e62e79457 Merge pull request #155 from kennytm/bug3952d_ctfeWriteln_again fix Issue 3952 part 4: Add __ctfeWrite and __ctfeWriteln.
Is this resolved now?
(In reply to comment #10) > Is this resolved now? - - - - - - - - - - - - - - - - - This doesn't work: __ctfeWriteln("hello"); void main() {} It gives: temp.d(1): Error: unexpected ( in declarator temp.d(1): Error: basic type expected, not "hello" temp.d(1): Error: found '"hello"' when expecting ')' temp.d(1): Error: no identifier for declarator __ctfeWriteln(int) temp.d(1): Error: semicolon expected following function declaration temp.d(1): Error: Declaration expected, not ')' - - - - - - - - - - - - - - - - - While this gives no errors but prints nothing: int foo() { __ctfeWriteln(1); __ctfeWriteln("hello"); return 0; } enum x = foo(); void main() {} - - - - - - - - - - - - - - - - - I don't like the names __ctfeWriteln and __ctfeWrite, they are ugly. It's much better to call them ctWriteln and ctWrite. They are meant to be a clean and handy feature of the D language, not some temporary compiler-speciic hack. - - - - - - - - - - - - - - - - - I don't see the D docs about those two functions in the D site. They need to be documented. - - - - - - - - - - - - - - - - - So this is not resolved yet.
Ok I can see now the Druntime pull was merged by accident. We're waiting for https://github.com/D-Programming-Language/dmd/pull/692
(In reply to comment #12) > Ok I can see now the Druntime pull was merged by accident. We're waiting for > https://github.com/D-Programming-Language/dmd/pull/692 Right. I don't know if this is supposed to work: __ctfeWriteln("hello"); void main() {} Regarding the bad __ctfeWriteln/__ctfeWrite names, I don't know what to do.
This is getting out of scope real quick. First the code: string foo0() { return "this is a test"; } string foo1() { return ""; } string foo2() { string result; return result; } string foo3() { return []; } pragma(msg, foo0()); pragma(msg, foo1()); pragma(msg, foo2()); pragma(msg, foo3()); //string hello = "red"; //pragma(msg, hello); pragma(msg, 12); void main() {} Now works as expected no [] literals. Except for static `hello`. __ctfeWrite is a separate issue so no point in doing it here. Lastly any bugs in pragma(msg, ...) are welcome as specific bugs.