www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Is there any hope for "lazy" and nogc?

reply Shachar Shemesh <shachar weka.io> writes:
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
Jul 31 2018
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
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.
Jul 31 2018
prev sibling next sibling parent reply Mike Franklin <slavo5150 yahoo.com> writes:
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
Jul 31 2018
parent reply Shachar Shemesh <shachar weka.io> writes:
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
Jul 31 2018
next sibling parent Guillaume Boucher <guillaume.boucher.d outlook.com> writes:
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 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.
Jul 31 2018
prev sibling parent Seb <seb wilzba.ch> writes:
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).
Jul 31 2018
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
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
Jul 31 2018
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
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
Jul 31 2018
prev sibling next sibling parent reply ag0aep6g <anonymous example.com> writes:
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
Jul 31 2018
next sibling parent reply Shachar Shemesh <shachar weka.io> writes:
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
Aug 01 2018
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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
Aug 01 2018
next sibling parent reply Shachar Shemesh <shachar weka.io> writes:
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.
Aug 01 2018
parent reply Iain Buclaw <ibuclaw gdcproject.org> writes:
On 1 August 2018 at 18:52, Shachar Shemesh via Digitalmars-d
<digitalmars-d puremagic.com> 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.
Aug 01 2018
parent reply Seb <seb wilzba.ch> writes:
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 
 <digitalmars-d puremagic.com> 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?
Aug 02 2018
parent Iain Buclaw <ibuclaw gdcproject.org> writes:
On 2 August 2018 at 16:14, Seb via Digitalmars-d
<digitalmars-d puremagic.com> 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
 <digitalmars-d puremagic.com> 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.
Aug 03 2018
prev sibling parent reply Shachar Shemesh <shachar weka.io> writes:
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
Aug 01 2018
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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
Aug 02 2018
next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
Aug 04 2018
parent Steven Schveighoffer <schveiguy gmail.com> writes:
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
Aug 04 2018
prev sibling parent Jacob Carlborg <doob me.com> writes:
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
Aug 04 2018
prev sibling parent Nick Treleaven <nick geany.org> writes:
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
Aug 05 2018
prev sibling parent Jacob Carlborg <doob me.com> writes:
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
Aug 04 2018