Is there any hope for "lazy" and @nogc?
I'm trying to figure out what's the signature of the built-in assert. It does not seem that I can define a similar function myself. First attempt: void myAssert(bool cond, string msg) @nogc nothrow; No, because msg gets evaluated unconditionally. void myAssert(bool cond, lazy string msg) @nogc nothrow; test.d(8): Error: @nogc function test.myAssert cannot call non-@nogc delegate msg void myAssert(bool cond, lazy string msg @nogc nothrow ) @nogc nothrow; test.d(4): Error: found @ when expecting ) test.d(4): Error: semicolon expected following function declaration test.d(4): Error: no identifier for declarator nogc test.d(4): Error: declaration expected, not ) test.d(9): Error: unrecognized declaration Templates to the rescue!!! void myAssert(STR)(bool cond, lazy STR msg ); test.d(14): Error: @nogc function D main cannot call non-@nogc function test.myAssert!string.myAssert Help?? Shachar
Re: Is there any hope for "lazy" and @nogc?
On 31/07/2018 7:17 PM, Shachar Shemesh wrote: I'm trying to figure out what's the signature of the built-in assert. It does not seem that I can define a similar function myself. That is because it isn't a function. It's a language feature that is backed by functions.
Re: Is there any hope for "lazy" and @nogc?
On Tuesday, 31 July 2018 at 07:17:34 UTC, Shachar Shemesh wrote: I'm trying to figure out what's the signature of the built-in assert. It does not seem that I can define a similar function myself. Help?? I'm not sure why you want a different assert, but you can consider these options. 1) Assign your own assert handler: https://github.com/dlang/druntime/blob/52d3fe02272d16d32c150ce6f78bc00241a9dd5d/src/core/exception.d#L393 2) You can provide your own implementations of the runtime hooks at https://github.com/dlang/druntime/blob/cb5efa9854775c5a72acd6870083b16e5ebba369/src/core/exception.d#L628 extern(C) void _d_assertp(immutable(char)* file, uint line) { import core.stdc.stdio; printf("Houston, we have a problem at %s:%u\n", file, line); } void main() { assert(false); } https://run.dlang.io/is/QZEO9W 3) -betterC seems to forward runtime assertions to the C implementation. See https://run.dlang.io/is/QZEO9W For that you have to provide a new implementation of `__assert`: extern(C) void __assert(const char *msg, const char *file, int line) { import core.stdc.stdio; printf("Houston, we have a problem at %s:%u\n", file, line); } extern(C) void main() { assert(false); } https://run.dlang.io/is/D5JxCT 4) Otherwise can't you just implement two `myAssert` overloads? `void assert(bool condition, string msg);` `void assert(bool condition)` Please clarify if I'm missing the point. Mike
Re: Is there any hope for "lazy" and @nogc?
On 31/07/18 10:29, Mike Franklin wrote: Please clarify if I'm missing the point. You are. I want something along the lines of: assertEQ(a, b, "a and b are not equal"); When run, it would issue an assert that says: Assertion failed: 3!=7: a and b are not equal Hooking it later is not an option. I am actually interested in a different assert like function. Whether for asserts or otherwise, the "lazy" feature is completely incompatible with function attributes, and that's not good. Shachar
Re: Is there any hope for "lazy" and @nogc?
On Tuesday, 31 July 2018 at 07:49:40 UTC, Shachar Shemesh wrote: On 31/07/18 10:29, Mike Franklin wrote: Please clarify if I'm missing the point. You are. I want something along the lines of: assertEQ(a, b, "a and b are not equal"); When run, it would issue an assert that says: Assertion failed: 3!=7: a and b are not equal What D really needs is power asserts. assertEQ's and its companions (assertLT, assertLE, ...) feel just like hacks. Power asserts come from Groovy and look like this (http://groovy-lang.org/semantics.html#_power_assertion): assert calc(x,y) == [x,z].sum() || | | | | | 15 2 7 | 2 5 7 false A poorer version exists in C++ (https://www.boost.org/doc/libs/1_67_0/libs/test/doc/html/boost_test/testing_tools/boost_test_universal_macro.html) and of course any language with decent metaprogramming facilities can implement them as a library solution (such as Rust: https://github.com/gifnksm/power-assert-rs and Go: https://github.com/ToQoz/gopwt). If you can not go the route of metaprogramming, provide an assert backend (Javascript: https://github.com/power-assert-js/power-assert). D needs something like this as well, and you can not get there just with lazy.
Re: Is there any hope for "lazy" and @nogc?
On 2018-07-31 09:17, Shachar Shemesh wrote: I'm trying to figure out what's the signature of the built-in assert. It does not seem that I can define a similar function myself. First attempt: void myAssert(bool cond, string msg) @nogc nothrow; No, because msg gets evaluated unconditionally. void myAssert(bool cond, lazy string msg) @nogc nothrow; test.d(8): Error: @nogc function test.myAssert cannot call non-@nogc delegate msg void myAssert(bool cond, lazy string msg @nogc nothrow ) @nogc nothrow; test.d(4): Error: found @ when expecting ) test.d(4): Error: semicolon expected following function declaration test.d(4): Error: no identifier for declarator nogc test.d(4): Error: declaration expected, not ) test.d(9): Error: unrecognized declaration Templates to the rescue!!! void myAssert(STR)(bool cond, lazy STR msg ); test.d(14): Error: @nogc function D main cannot call non-@nogc function test.myAssert!string.myAssert It seems this is a limitation in the syntax. It works with an explicit delegate, but then that is required at the call site as well. A lazy parameter is basically just a delegate with a nicer syntax. void myAssert(bool cond, string delegate() @nogc nothrow msg) @nogc nothrow { auto a = msg(); } Support for adding UDAs to function parameters was recently added. Perhaps we need to support other attributes as well. Please report an issue to http://issues.dlang.org. -- /Jacob Carlborg
Re: Is there any hope for "lazy" and @nogc?
On Tuesday, 31 July 2018 at 07:49:40 UTC, Shachar Shemesh wrote: On 31/07/18 10:29, Mike Franklin wrote: Please clarify if I'm missing the point. You are. I want something along the lines of: assertEQ(a, b, "a and b are not equal"); When run, it would issue an assert that says: Assertion failed: 3!=7: a and b are not equal You could also vote for this PR (https://github.com/dlang/dmd/pull/8517) - this PR will generate such error messages. It's intended to work in -betterC and @nogc (once the PR is ready).
Re: Is there any hope for "lazy" and @nogc?
On 7/31/18 3:17 AM, Shachar Shemesh wrote: I'm trying to figure out what's the signature of the built-in assert. It does not seem that I can define a similar function myself. First attempt: void myAssert(bool cond, string msg) @nogc nothrow; No, because msg gets evaluated unconditionally. void myAssert(bool cond, lazy string msg) @nogc nothrow; test.d(8): Error: @nogc function test.myAssert cannot call non-@nogc delegate msg Hm... I would say compiler should be smart enough to know that lazy string messages that are not @nogc shouldn't be able to be passed in here. e.g.: myAssert(a == b, "a and b should be equal); // ok myAssert(a == b, a.name ~ " and " ~ b.name ~ " should be equal"); // error It appears that lazy is not inferring anything, it's strictly transformed into a normal delegate. I'd say at least the template solution should be made to work. -Steve
Re: Is there any hope for "lazy" and @nogc?
On 07/31/2018 09:17 AM, Shachar Shemesh wrote: I'm trying to figure out what's the signature of the built-in assert. It does not seem that I can define a similar function myself. Looks like you can do it with a "lazy variadic function" [1], but it's not pretty: alias Dg = string delegate() @nogc nothrow; void myAssert(bool cond, Dg[1] msg_dg ...) @nogc nothrow { import core.stdc.stdio; if (!cond) { string msg = msg_dg[0](); printf("%*s\n", msg.length, msg.ptr); } } [1] https://dlang.org/spec/function.html#lazy_variadic_functions
Re: Is there any hope for "lazy" and @nogc?
Thank you! Finally! Let me just state, for the record, that having *yet another* syntax special case is just appalling. With that said, I was hoping that specifying it explicitly as a delegate would allow me to scope it. Apparently, that doesn't work :-( Shachar On 31/07/18 23:03, ag0aep6g wrote: On 07/31/2018 09:17 AM, Shachar Shemesh wrote: I'm trying to figure out what's the signature of the built-in assert. It does not seem that I can define a similar function myself. Looks like you can do it with a "lazy variadic function" [1], but it's not pretty: alias Dg = string delegate() @nogc nothrow; void myAssert(bool cond, Dg[1] msg_dg ...) @nogc nothrow { import core.stdc.stdio; if (!cond) { string msg = msg_dg[0](); printf("%*s\n", msg.length, msg.ptr); } } [1] https://dlang.org/spec/function.html#lazy_variadic_functions
Re: Is there any hope for "lazy" and @nogc?
On 8/1/18 3:59 AM, Shachar Shemesh wrote: Thank you! Finally! Let me just state, for the record, that having *yet another* syntax special case is just appalling. The lazy variadic thing is a distinction between specifying variadic lazy parameters and a lazy variadic array. The distinction is so miniscule, but necessary to have a disambiguous syntax. But I had actually thought for a while, that you could simply specify a delegate, and it would be treated as a lazy parameter, which would probably solve your problem. I really think this syntax should be available. With that said, I was hoping that specifying it explicitly as a delegate would allow me to scope it. Apparently, that doesn't work :-( I guess you mean you can't scope the delegates? I'm surprised if that doesn't work. -Steve
Re: Is there any hope for "lazy" and @nogc?
On 01/08/18 17:13, Steven Schveighoffer wrote: On 8/1/18 3:59 AM, Shachar Shemesh wrote: Thank you! Finally! Let me just state, for the record, that having *yet another* syntax special case is just appalling. The lazy variadic thing is a distinction between specifying variadic lazy parameters and a lazy variadic array. The distinction is so miniscule, but necessary to have a disambiguous syntax. But I had actually thought for a while, that you could simply specify a delegate, and it would be treated as a lazy parameter, which would probably solve your problem. I really think this syntax should be available. With that said, I was hoping that specifying it explicitly as a delegate would allow me to scope it. Apparently, that doesn't work :-( I guess you mean you can't scope the delegates? I'm surprised if that doesn't work. -Steve import std.string; alias Dg = string delegate() @nogc nothrow; void myAssert(bool cond, scope Dg[1] msg_dg ...) @nogc nothrow { import core.stdc.stdio; if (!cond) { string msg = msg_dg[0](); printf("%*s\n", msg.length, msg.ptr); } } void main() @nogc { string msg = "Hello"; myAssert(true, msg); // <- errors on this line } It errors out: complains it needs to allocate main's frame on the GC, but main is @nogc. The same happens if I move the scope to the alias.
Re: Is there any hope for "lazy" and @nogc?
On 1 August 2018 at 18:52, Shachar Shemesh via Digitalmars-d wrote: > On 01/08/18 17:13, Steven Schveighoffer wrote: >> >> On 8/1/18 3:59 AM, Shachar Shemesh wrote: >>> >>> Thank you! Finally! >>> >>> Let me just state, for the record, that having *yet another* syntax >>> special case is just appalling. >> >> >> The lazy variadic thing is a distinction between specifying variadic lazy >> parameters and a lazy variadic array. The distinction is so miniscule, but >> necessary to have a disambiguous syntax. >> >> But I had actually thought for a while, that you could simply specify a >> delegate, and it would be treated as a lazy parameter, which would probably >> solve your problem. I really think this syntax should be available. >> >>> With that said, I was hoping that specifying it explicitly as a delegate >>> would allow me to scope it. Apparently, that doesn't work :-( >>> >> >> I guess you mean you can't scope the delegates? I'm surprised if that >> doesn't work. >> >> -Steve > > > > > import std.string; > > alias Dg = string delegate() @nogc nothrow; > > void myAssert(bool cond, scope Dg[1] msg_dg ...) @nogc nothrow > { > import core.stdc.stdio; > if (!cond) > { > string msg = msg_dg[0](); > printf("%*s\n", msg.length, msg.ptr); > } > } > > void main() @nogc { > string msg = "Hello"; > myAssert(true, msg); // <- errors on this line > } > > It errors out: complains it needs to allocate main's frame on the GC, but > main is @nogc. The same happens if I move the scope to the alias. My first thought was to have a look at enforce(), but on closer observation it is neither @nogc or nothrow. Maybe you should raise a bug report? It's certainly worth an attempt to bridge these two features together. I think it makes sense enough that lazy parameters should infer attributes from the function, and that it should be an error to pass a parameter that does not meet those constraints. i.e: --- // Signatures. void myAssert(bool cond, lazy string msg) @nogc nothrow; string mayAlloc() nothrow; string mayThrow() @nogc; // Code myAssert(cond, mayAlloc());// violates @nogc myAssert(cond, mayThrow());// violates nothrow --- Iain.
Re: Is there any hope for "lazy" and @nogc?
On 01/08/18 17:13, Steven Schveighoffer wrote: The lazy variadic thing is a distinction between specifying variadic lazy parameters and a lazy variadic array. I have now read that sentence 4 times, and I still have no idea what it means. Can you give examples of both? Shachar
Re: Is there any hope for "lazy" and @nogc?
On 8/1/18 10:14 PM, Shachar Shemesh wrote: On 01/08/18 17:13, Steven Schveighoffer wrote: The lazy variadic thing is a distinction between specifying variadic lazy parameters and a lazy variadic array. I have now read that sentence 4 times, and I still have no idea what it means. Can you give examples of both? import std.stdio; // lazy variadic array void foo(lazy int[] arr...) { writeln(arr[0]); writeln(arr[1]); writeln(arr[2]); } // variadic lazy paramters void bar(int delegate()[] items...) { writeln(items[0]()); writeln(items[1]()); writeln(items[2]()); } int param(int x) { writeln("param ", x); return x; } void main() { foo(param(0), param(1), param(2)); bar(param(0), param(1), param(2)); } output: param 0 param 1 param 2 0 param 0 param 1 param 2 1 param 0 param 1 param 2 2 param 0 0 param 1 1 param 2 2 So in the first case, the ENTIRE array is evaluated lazily, and then an element selected. In the second case, each item is evaluated when used. -Steve
Re: Is there any hope for "lazy" and @nogc?
On Wednesday, 1 August 2018 at 20:32:11 UTC, Iain Buclaw wrote: On 1 August 2018 at 18:52, Shachar Shemesh via Digitalmars-d wrote: [...] My first thought was to have a look at enforce(), but on closer observation it is neither @nogc or nothrow. Maybe you should raise a bug report? It's certainly worth an attempt to bridge these two features together. I think it makes sense enough that lazy parameters should infer attributes from the function, and that it should be an error to pass a parameter that does not meet those constraints. i.e: --- // Signatures. void myAssert(bool cond, lazy string msg) @nogc nothrow; string mayAlloc() nothrow; string mayThrow() @nogc; // Code myAssert(cond, mayAlloc());// violates @nogc myAssert(cond, mayThrow());// violates nothrow --- Iain. Isn't this https://issues.dlang.org/show_bug.cgi?id=12647?
Re: Is there any hope for "lazy" and @nogc?
On 2 August 2018 at 16:14, Seb via Digitalmars-d wrote: > On Wednesday, 1 August 2018 at 20:32:11 UTC, Iain Buclaw wrote: >> >> On 1 August 2018 at 18:52, Shachar Shemesh via Digitalmars-d >> wrote: >>> >>> [...] >> >> >> My first thought was to have a look at enforce(), but on closer >> observation it is neither @nogc or nothrow. >> >> Maybe you should raise a bug report? >> >> It's certainly worth an attempt to bridge these two features together. I >> think it makes sense enough that lazy parameters should infer attributes >> from the function, and that it should be an error to pass a parameter that >> does not meet those constraints. >> >> i.e: >> --- >> // Signatures. >> void myAssert(bool cond, lazy string msg) @nogc nothrow; >> string mayAlloc() nothrow; >> string mayThrow() @nogc; >> >> // Code >> myAssert(cond, mayAlloc());// violates @nogc >> myAssert(cond, mayThrow());// violates nothrow >> --- >> >> Iain. > > > Isn't this https://issues.dlang.org/show_bug.cgi?id=12647? Seems so, good to know. I'll bookmark it for when I get time to do other things. Iain.
Re: Is there any hope for "lazy" and @nogc?
On 2018-08-02 13:33, Steven Schveighoffer wrote: // variadic lazy paramters void bar(int delegate()[] items...) { writeln(items[0]()); writeln(items[1]()); writeln(items[2]()); } Adding @nogc to this example works. -- /Jacob Carlborg
Re: Is there any hope for "lazy" and @nogc?
On 2018-08-02 13:33, Steven Schveighoffer wrote: // variadic lazy paramters void bar(int delegate()[] items...) { writeln(items[0]()); writeln(items[1]()); writeln(items[2]()); } I'm surprised that this doesn't need to be called with a delegate syntax, i.e. bar({ return 0; }); -- /Jacob Carlborg
Re: Is there any hope for "lazy" and @nogc?
On 8/4/18 3:07 PM, Jacob Carlborg wrote: On 2018-08-02 13:33, Steven Schveighoffer wrote: // variadic lazy paramters void bar(int delegate()[] items...) { writeln(items[0]()); writeln(items[1]()); writeln(items[2]()); } I'm surprised that this doesn't need to be called with a delegate syntax, i.e. bar({ return 0; }); See one of the earlier posts, it's a lazy variadic function. A little-known D feature. -Steve
Re: Is there any hope for "lazy" and @nogc?
On 2018-07-31 09:17, Shachar Shemesh wrote: I'm trying to figure out what's the signature of the built-in assert. It does not seem that I can define a similar function myself. First attempt: void myAssert(bool cond, string msg) @nogc nothrow; No, because msg gets evaluated unconditionally. void myAssert(bool cond, lazy string msg) @nogc nothrow; test.d(8): Error: @nogc function test.myAssert cannot call non-@nogc delegate msg void myAssert(bool cond, lazy string msg @nogc nothrow ) @nogc nothrow; test.d(4): Error: found @ when expecting ) test.d(4): Error: semicolon expected following function declaration test.d(4): Error: no identifier for declarator nogc test.d(4): Error: declaration expected, not ) test.d(9): Error: unrecognized declaration Templates to the rescue!!! void myAssert(STR)(bool cond, lazy STR msg ); test.d(14): Error: @nogc function D main cannot call non-@nogc function test.myAssert!string.myAssert Based on what Steven said and what I found in the spec, this seems to work with the current language [1]: extern (C) int printf(in char*, ...) @nogc nothrow; void myAssert(bool cond, string delegate() @nogc nothrow[1] msg ...) @nogc nothrow { msg[0](); } string param() @nogc nothrow { printf("bar\n"); return "foo"; } void main() @nogc nothrow { myAssert(false, param()); } This prints "bar". But if the delegate is not called, then nothing is printed. The signature of "myAssert" is bit ugly and not straightforward to understand, but it works. I think it should be possible to specify attributes for lazy parameters or they should be automatically inferred. Is there an issue for this reported? [1] https://run.dlang.io/is/g4Rm1w -- /Jacob Carlborg
Re: Is there any hope for "lazy" and @nogc?
On Tuesday, 31 July 2018 at 20:03:39 UTC, ag0aep6g wrote: Looks like you can do it with a "lazy variadic function" [1], Interesting, thanks. I've made a pull to add a See Also link about this to the Lazy Parameters docs: https://github.com/dlang/dlang.org/pull/2439