digitalmars.D.learn - How do you debug safe nogc code? Can't figure out how to print.
- aliak (47/47) Nov 16 2018 Hi, I previously had trouble trying to get print statements
- Zoadian (4/4) Nov 16 2018 debug {
- aliak (2/6) Nov 17 2018 As mentioned in the original post, that does not work.
- Stanislav Blinov (16/30) Nov 16 2018 As Zoadian points out, you can now (since 2.079:
- aliak (7/17) Nov 17 2018 Sawweet! Thanks, that made the printing possible!
- Stanislav Blinov (17/20) Nov 17 2018 You're welcome ;) Still, try a more recent compiler. This works
- aliak (10/31) Nov 17 2018 Yeah that does, but not the code I posted ->
- Stanislav Blinov (5/10) Nov 17 2018 Indeed that fails, and I would say that's a bug. If it's allowed
- Neia Neutuladh (4/7) Nov 17 2018 You can explicitly mark a templated function as @nogc. If you want your
- aliak (5/14) Nov 17 2018 Could do. But it's not scalable. I'd have to comment out all the
- Neia Neutuladh (19/22) Nov 17 2018 I meant something like:
- aliak (4/27) Nov 18 2018 Aha! I misunderstood what you meant. Yes that's actually simpler
- Vijay Nayar (4/34) Nov 22 2018 Alternatively, you can use the core.stc libraries, which do not
- Nicholas Wilson (4/10) Nov 17 2018 No, `in` used to mean const scope.
- aliak (3/15) Nov 17 2018 Righto! Thanks!
Hi, I previously had trouble trying to get print statements working while debugging in nogc. And that was hackishly solved [0], but I can't figure out how to do the same if I have safe involved. Here's a cut down sample: // This is the function from the thread referenced auto assumeNoGC(T)(T t) { import std.traits; enum attrs = functionAttributes!T | FunctionAttribute.nogc; return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t; } private struct Dispatcher { public template opDispatch(string name){ auto ref opDispatch(Args...)(auto ref Args args) { import std.stdio; // Print args here for debugging purposes assumeNoGC({ writeln(args); })(); return 3; } } } safe nogc void main() { auto i = Dispatcher().getI(3); } So, basically with the above, using: debug writeln(args); Causes "Error: nogc function D main cannot call non- nogc function" Using: debug assumeNoGC({ writeln(args); })(); Causes: Error: safe function D main cannot call system function Error: nogc function D main cannot call non- nogc function Changing attrs in assumeNoGC enum attrs = functionAttributes!T | FunctionAttribute.nogc | FunctionAttribute.safe Causes same as previous errors Adding trusted to declaration of opDispatch gets rid of safe error but I still get "Error: nogc function D main cannot call non- nogc function". And going through the codebase and figuring out where to add trusted is *very* cumbersome. I can't figure out how to make this work. The ideal way would be just a debug_print() function that works in nogc and safe code. I.e. does not affect the attribute inference of templates. Cheers, - Ali [0] https://forum.dlang.org/post/pmf4dm$jmo$1 digitalmars.com
Nov 16 2018
On Friday, 16 November 2018 at 13:03:40 UTC, Zoadian wrote:debug { import std.stdio; writeln(args); }As mentioned in the original post, that does not work.
Nov 17 2018
On Friday, 16 November 2018 at 12:59:22 UTC, aliak wrote:Adding trusted to declaration of opDispatch gets rid of safe error but I still get "Error: nogc function D main cannot call non- nogc function". And going through the codebase and figuring out where to add trusted is *very* cumbersome. I can't figure out how to make this work. The ideal way would be just a debug_print() function that works in nogc and safe code. I.e. does not affect the attribute inference of templates.As Zoadian points out, you can now (since 2.079: https://dlang.org/changelog/2.079.0.html#bugfix-list) shamelessly call nogc inside debug blocks. To get at where the problematic areas were in the code in question though, it's as follows:auto assumeNoGC(T)(T t) { // point 1 import std.traits; enum attrs = functionAttributes!T | FunctionAttribute.nogc; // point 2: return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t; }At 'point 1', you just take by value. If `t` ends up being a closure, D will allocate. That's where it breaks the nogc. Solution: auto assumeNoGC(T)(return scope T t) { /* ... */ } Now you take (and return) a `scope` t, in that case when `t` is a closure D won't allocate it on the GC heap. At 'point 2' you make an un- safe cast, that's where it breaks safe. Given that the whole deal is just a debugging hack, you could mark the whole function trusted: auto assumeNoGC(T)(return scope T t) trusted { /* ... */ }
Nov 16 2018
On Friday, 16 November 2018 at 13:21:39 UTC, Stanislav Blinov wrote:At 'point 1', you just take by value. If `t` ends up being a closure, D will allocate. That's where it breaks the nogc. Solution: auto assumeNoGC(T)(return scope T t) { /* ... */ } Now you take (and return) a `scope` t, in that case when `t` is a closure D won't allocate it on the GC heap. At 'point 2' you make an un- safe cast, that's where it breaks safe. Given that the whole deal is just a debugging hack, you could mark the whole function trusted: auto assumeNoGC(T)(return scope T t) trusted { /* ... */ }Sawweet! Thanks, that made the printing possible! "scope" is const from what I understand right? It works without scope as well. So just "return T". Cheers, - Ali
Nov 17 2018
On Saturday, 17 November 2018 at 13:13:36 UTC, aliak wrote:Sawweet! Thanks, that made the printing possible!You're welcome ;) Still, try a more recent compiler. This works fine: void foo() nogc { debug { import std.stdio; writefln("%d", 42); } }"scope" is const from what I understand right? It works without scope as well. So just "return T".No, "scope" means "does not escape scope", i.e. you can't assign that argument to some global. The only exception is through a return, in which case "return" also needed. Whether or not just "return" is sufficient, is a bit out there still (AFAIK), between DIP25, DIP1000 and current state of the language. "scope" was implemented for delegates for ages now, exactly to allow passing lambdas around without allocating their context on the GC heap.
Nov 17 2018
On Saturday, 17 November 2018 at 13:43:20 UTC, Stanislav Blinov wrote:On Saturday, 17 November 2018 at 13:13:36 UTC, aliak wrote:Yeah that does, but not the code I posted -> https://run.dlang.io/is/vH3cFa You can use "debug blah" to hide inside functions that are attributed, but when you have an attributed function that calls a template, attribtues of which are supposed to be inferred, it seems to fail. Maybe a bug if it's supposed to work?Sawweet! Thanks, that made the printing possible!You're welcome ;) Still, try a more recent compiler. This works fine: void foo() nogc { debug { import std.stdio; writefln("%d", 42); } }Aha, cool. Thanks!"scope" is const from what I understand right? It works without scope as well. So just "return T".No, "scope" means "does not escape scope", i.e. you can't assign that argument to some global. The only exception is through a return, in which case "return" also needed. Whether or not just "return" is sufficient, is a bit out there still (AFAIK), between DIP25, DIP1000 and current state of the language. "scope" was implemented for delegates for ages now, exactly to allow passing lambdas around without allocating their context on the GC heap.
Nov 17 2018
On Saturday, 17 November 2018 at 13:55:24 UTC, aliak wrote:You can use "debug blah" to hide inside functions that are attributed, but when you have an attributed function that calls a template, attribtues of which are supposed to be inferred, it seems to fail. Maybe a bug if it's supposed to work?Indeed that fails, and I would say that's a bug. If it's allowed in nogc, it shouldn't then infer to non- nogc when not explicitly attributed. Maybe debug blocks should outright be skipped when inferring?..
Nov 17 2018
On Sat, 17 Nov 2018 13:55:24 +0000, aliak wrote:You can use "debug blah" to hide inside functions that are attributed, but when you have an attributed function that calls a template, attribtues of which are supposed to be inferred, it seems to fail.You can explicitly mark a templated function as nogc. If you want your function's nogc-ness inferred, you can pull out the debug logging into a separate function and explicitly mark it nogc.
Nov 17 2018
On Saturday, 17 November 2018 at 17:48:43 UTC, Neia Neutuladh wrote:On Sat, 17 Nov 2018 13:55:24 +0000, aliak wrote:Could do. But it's not scalable. I'd have to comment out all the unittests that call the template function with a T that allocates inside the nogc template (if I understood you correctly that it)You can use "debug blah" to hide inside functions that are attributed, but when you have an attributed function that calls a template, attribtues of which are supposed to be inferred, it seems to fail.You can explicitly mark a templated function as nogc. If you want your function's nogc-ness inferred, you can pull out the debug logging into a separate function and explicitly mark it nogc.
Nov 17 2018
On Sat, 17 Nov 2018 21:16:13 +0000, aliak wrote:Could do. But it's not scalable. I'd have to comment out all the unittests that call the template function with a T that allocates inside the nogc template (if I understood you correctly that it)I meant something like: void debugln(T...)(T args) nogc { import std.stdio; debug(MyProject) writeln(args); } You use that function instead of writeln in your nogc-compatible templates: void callFunc(alias func)() { debugln("about to call function!"); func(); debugln("done calling function!"); } Then I can write: nogc: void foo() { printf("hello world\n"); } void main() { callFunc!foo(); }
Nov 17 2018
On Saturday, 17 November 2018 at 21:56:23 UTC, Neia Neutuladh wrote:On Sat, 17 Nov 2018 21:16:13 +0000, aliak wrote:Aha! I misunderstood what you meant. Yes that's actually simpler that what I was doing :D Thanks!Could do. But it's not scalable. I'd have to comment out all the unittests that call the template function with a T that allocates inside the nogc template (if I understood you correctly that it)I meant something like: void debugln(T...)(T args) nogc { import std.stdio; debug(MyProject) writeln(args); } You use that function instead of writeln in your nogc-compatible templates: void callFunc(alias func)() { debugln("about to call function!"); func(); debugln("done calling function!"); } Then I can write: nogc: void foo() { printf("hello world\n"); } void main() { callFunc!foo(); }
Nov 18 2018
On Sunday, 18 November 2018 at 11:00:26 UTC, aliak wrote:On Saturday, 17 November 2018 at 21:56:23 UTC, Neia Neutuladh wrote:Alternatively, you can use the core.stc libraries, which do not depend on the GC, for debugging. https://dlang.org/phobos/core_stdc_stdio.html#.printfOn Sat, 17 Nov 2018 21:16:13 +0000, aliak wrote:Aha! I misunderstood what you meant. Yes that's actually simpler that what I was doing :D Thanks![...]I meant something like: void debugln(T...)(T args) nogc { import std.stdio; debug(MyProject) writeln(args); } You use that function instead of writeln in your nogc-compatible templates: void callFunc(alias func)() { debugln("about to call function!"); func(); debugln("done calling function!"); } Then I can write: nogc: void foo() { printf("hello world\n"); } void main() { callFunc!foo(); }
Nov 22 2018
On Saturday, 17 November 2018 at 13:13:36 UTC, aliak wrote:On Friday, 16 November 2018 at 13:21:39 UTC, Stanislav Blinov wrote:No, `in` used to mean const scope. scope means roughly "this thing does not escape this function" e.g. assigning to global variables.auto assumeNoGC(T)(return scope T t) trusted { /* ... */ }Sawweet! Thanks, that made the printing possible! "scope" is const from what I understand right? It works without scope as well. So just "return T".
Nov 17 2018
On Saturday, 17 November 2018 at 13:46:00 UTC, Nicholas Wilson wrote:On Saturday, 17 November 2018 at 13:13:36 UTC, aliak wrote:Righto! Thanks!On Friday, 16 November 2018 at 13:21:39 UTC, Stanislav Blinov wrote:No, `in` used to mean const scope. scope means roughly "this thing does not escape this function" e.g. assigning to global variables.auto assumeNoGC(T)(return scope T t) trusted { /* ... */ }Sawweet! Thanks, that made the printing possible! "scope" is const from what I understand right? It works without scope as well. So just "return T".
Nov 17 2018