digitalmars.D - Expressing range constraints in CNF form
- Andrei Alexandrescu (28/28) Jun 10 2017 https://github.com/dlang/phobos/pull/5461
- Nick Treleaven (4/17) Jun 11 2017 Great!
- Andrei Alexandrescu (7/25) Jun 11 2017 Ostensibly the function is trivial:
- Stefan Koch (4/33) Jun 11 2017 Exposing magic functions which are recognized by name strikes me
- Andrei Alexandrescu (6/8) Jun 11 2017 This is brainstorming. Let's follow up with better ideas in addition to
- Timon Gehr (5/37) Jun 11 2017 I'd prefer
- Stanislav Blinov (3/8) Jun 11 2017 Where were you while Steven was destroying me? :)
- Steven Schveighoffer (8/18) Jun 11 2017 Heh, I both like the idea of switching the constraints to something that...
- Andrei Alexandrescu (2/3) Jun 11 2017 That'd be nice to consider, too, thanks. -- Andrei
- Antonio Corbi (10/26) Jun 11 2017 So this is trying to parafrase the perl/bash idiom:
- Walter Bright (7/13) Jun 11 2017 There was a proposal a while back to enable CTFE to print messages, whic...
- ketmar (4/17) Jun 11 2017 that has another problem: there may be overload set, where some overload...
- ketmar (6/19) Jun 11 2017 i think, that something like `__constraint(condition, "message")` is ok,...
- Stefan Koch (3/11) Jun 11 2017 +1
- bachmeier (2/8) Jun 11 2017 This is really nice. I like it better than my suggestion.
- bachmeier (6/15) Jun 11 2017 This would be a very nice change, but this syntax feels more
- crimaniak (9/11) Jun 11 2017 Regardless of the implementation method, this will require the
- Walter Bright (3/8) Jun 11 2017 You're right that there are issues with the `msg` thing in the presence ...
- Walter Bright (5/6) Jun 11 2017 Wouldn't it work better as:
- Stefan Koch (4/12) Jun 11 2017 I can do a __ctfePrint for string literals.
- Andrei Alexandrescu (2/12) Jun 11 2017 The added parens are a small liability. -- Andrei
- Sebastiaan Koppe (9/18) Jun 11 2017 What about using ddoc?
- David Gileadi (4/12) Jun 12 2017 If there's going to be compiler magic, this seems like a sensible
- Sebastiaan Koppe (4/16) Jun 12 2017 Yeah, I had meant to mention the compiler magic involved. I
- H. S. Teoh via Digitalmars-d (7/21) Jun 12 2017 +1, I like this idea much better than any of the others proposed so far.
- Adam D. Ruppe (10/15) Jun 11 2017 Or how about
- Steven Schveighoffer (4/19) Jun 11 2017 Exactly my point.
- Walter Bright (4/5) Jun 12 2017 That doesn't work because there may be a local symbol:
- Steven Schveighoffer (6/11) Jun 12 2017 That is a problem regardless of the constraint.
- Andrei Alexandrescu (7/15) Jun 12 2017 Yah, this was part of the original design: migrate all checks to
https://github.com/dlang/phobos/pull/5461 There's many good advantages to this. The immediate one is the constraint is better structured and easier to understand. Then, the compiler can print the exact clause that failed, which improves the precision and quality of the error message. We consider adding in the future some capability of printing user-defined error messages, one per clause. For example: // Current enum bool isInputRange(R) = is(typeof((ref R r) => r)) && is(ReturnType!((R r) => r.empty) == bool) && is(typeof(lvalueOf!R.front)) && is(typeof(lvalueOf!R.popFront)); // Possible (which change to language) enum bool isInputRange(R) = is(typeof((ref R r) => r)) && "must be copyable" && is(ReturnType!((R r) => r.empty) == bool) && "must support bool empty" && is(typeof(lvalueOf!R.front)) && "must support front" && is(typeof(lvalueOf!R.popFront)) && "must support back"; // Also possible (no change to the language) enum bool isInputRange(R) = is(typeof((ref R r) => r)) && msg("must be copyable") && is(ReturnType!((R r) => r.empty) == bool) && msg("must support bool empty") && is(typeof(lvalueOf!R.front)) && msg("must support front") && is(typeof(lvalueOf!R.popFront)) && msg("must support back"); Andrei
Jun 10 2017
On Sunday, 11 June 2017 at 00:28:58 UTC, Andrei Alexandrescu wrote:https://github.com/dlang/phobos/pull/5461 There's many good advantages to this. The immediate one is the constraint is better structured and easier to understand. Then, the compiler can print the exact clause that failed, which improves the precision and quality of the error message.Great!// Also possible (no change to the language) enum bool isInputRange(R) = is(typeof((ref R r) => r)) && msg("must be copyable") && is(ReturnType!((R r) => r.empty) == bool) && msg("must support bool empty") && is(typeof(lvalueOf!R.front)) && msg("must support front") && is(typeof(lvalueOf!R.popFront)) && msg("must support back");I'm not getting how this works.
Jun 11 2017
On 6/11/17 11:11 AM, Nick Treleaven wrote:On Sunday, 11 June 2017 at 00:28:58 UTC, Andrei Alexandrescu wrote:Thanks.https://github.com/dlang/phobos/pull/5461 There's many good advantages to this. The immediate one is the constraint is better structured and easier to understand. Then, the compiler can print the exact clause that failed, which improves the precision and quality of the error message.Great!Ostensibly the function is trivial: bool msg(string) { return true; } It doesn't change the semantics. The compiler would recognize it as an intrinsic and would print the message if the clause to its left has failed. Andrei// Also possible (no change to the language) enum bool isInputRange(R) = is(typeof((ref R r) => r)) && msg("must be copyable") && is(ReturnType!((R r) => r.empty) == bool) && msg("must support bool empty") && is(typeof(lvalueOf!R.front)) && msg("must support front") && is(typeof(lvalueOf!R.popFront)) && msg("must support back");I'm not getting how this works.
Jun 11 2017
On Sunday, 11 June 2017 at 15:25:11 UTC, Andrei Alexandrescu wrote:On 6/11/17 11:11 AM, Nick Treleaven wrote:Exposing magic functions which are recognized by name strikes me as being worse then proper compiler intrinsics.On Sunday, 11 June 2017 at 00:28:58 UTC, Andrei Alexandrescu wrote:Thanks.https://github.com/dlang/phobos/pull/5461 There's many good advantages to this. The immediate one is the constraint is better structured and easier to understand. Then, the compiler can print the exact clause that failed, which improves the precision and quality of the error message.Great!Ostensibly the function is trivial: bool msg(string) { return true; } It doesn't change the semantics. The compiler would recognize it as an intrinsic and would print the message if the clause to its left has failed. Andrei// Also possible (no change to the language) enum bool isInputRange(R) = is(typeof((ref R r) => r)) && msg("must be copyable") && is(ReturnType!((R r) => r.empty) == bool) && msg("must support bool empty") && is(typeof(lvalueOf!R.front)) && msg("must support front") && is(typeof(lvalueOf!R.popFront)) && msg("must support back");I'm not getting how this works.
Jun 11 2017
On 6/11/17 12:15 PM, Stefan Koch wrote:Exposing magic functions which are recognized by name strikes me as being worse then proper compiler intrinsics.This is brainstorming. Let's follow up with better ideas in addition to pointing out flaws in the ideas on the table. To this point: .msg would solve the problem of "msg" being defined in the current scope (assuming of course msg is defined in object.d). Andrei
Jun 11 2017
On 11.06.2017 17:25, Andrei Alexandrescu wrote:On 6/11/17 11:11 AM, Nick Treleaven wrote:I'd prefer bool msg(bool constraint, string message){ return constraint; } This does not require the compiler to dive into a branch it wouldn't consider otherwise, and the pairing of constraint to message is less ad-hoc.On Sunday, 11 June 2017 at 00:28:58 UTC, Andrei Alexandrescu wrote:Thanks.https://github.com/dlang/phobos/pull/5461 There's many good advantages to this. The immediate one is the constraint is better structured and easier to understand. Then, the compiler can print the exact clause that failed, which improves the precision and quality of the error message.Great!Ostensibly the function is trivial: bool msg(string) { return true; } It doesn't change the semantics. The compiler would recognize it as an intrinsic and would print the message if the clause to its left has failed. Andrei// Also possible (no change to the language) enum bool isInputRange(R) = is(typeof((ref R r) => r)) && msg("must be copyable") && is(ReturnType!((R r) => r.empty) == bool) && msg("must support bool empty") && is(typeof(lvalueOf!R.front)) && msg("must support front") && is(typeof(lvalueOf!R.popFront)) && msg("must support back");I'm not getting how this works.
Jun 11 2017
On Sunday, 11 June 2017 at 16:28:23 UTC, Timon Gehr wrote:I'd prefer bool msg(bool constraint, string message){ return constraint; } This does not require the compiler to dive into a branch it wouldn't consider otherwise, and the pairing of constraint to message is less ad-hoc.Where were you while Steven was destroying me? :) http://forum.dlang.org/thread/mcxeymbslqtvfijxirmy forum.dlang.org
Jun 11 2017
On 6/11/17 12:35 PM, Stanislav Blinov wrote:On Sunday, 11 June 2017 at 16:28:23 UTC, Timon Gehr wrote:Heh, I both like the idea of switching the constraints to something that identifies easily a single test of the constraint instead of a lambda that can fail for any number of reasons, and also think we still do not need a message. i.e.: is(typeof(lvalueOf!R.front)) && "must support front" "must support front" seems pretty obvious from the test. -SteveI'd prefer bool msg(bool constraint, string message){ return constraint; } This does not require the compiler to dive into a branch it wouldn't consider otherwise, and the pairing of constraint to message is less ad-hoc.Where were you while Steven was destroying me? :) http://forum.dlang.org/thread/mcxeymbslqtvfijxirmy forum.dlang.org
Jun 11 2017
On 6/11/17 12:28 PM, Timon Gehr wrote:bool msg(bool constraint, string message){ return constraint; }That'd be nice to consider, too, thanks. -- Andrei
Jun 11 2017
On Sunday, 11 June 2017 at 15:25:11 UTC, Andrei Alexandrescu wrote:On 6/11/17 11:11 AM, Nick Treleaven wrote:So this is trying to parafrase the perl/bash idiom: ``` commandSucceeds (...) || die (); ``` Isn't it? So, the '&&' -and- shouldn't be '||' -or-? Sorry for the noise if I'm wrong. AntonioOn Sunday, 11 June 2017 at 00:28:58 UTC, Andrei Alexandrescu wrote:Thanks.[...]Great!Ostensibly the function is trivial: bool msg(string) { return true; } It doesn't change the semantics. The compiler would recognize it as an intrinsic and would print the message if the clause to its left has failed. Andrei[...]I'm not getting how this works.
Jun 11 2017
On 6/11/2017 8:25 AM, Andrei Alexandrescu wrote:Ostensibly the function is trivial: bool msg(string) { return true; } It doesn't change the semantics. The compiler would recognize it as an intrinsic and would print the message if the clause to its left has failed.There was a proposal a while back to enable CTFE to print messages, which is probably a better solution. msg() could be something along the lines of: bool msg(string) { __ctfeprint(string); return true; } which would involve considerably less compiler magic. Furthermore, `msg` could be a local private function, which would avoid "but I'm already using `msg`" problems.
Jun 11 2017
Walter Bright wrote:On 6/11/2017 8:25 AM, Andrei Alexandrescu wrote:that has another problem: there may be overload set, where some overloads are failed, but one is fitting. using `ctfeprint` will spam user with alot of non-sensical messages about failed constraints.Ostensibly the function is trivial: bool msg(string) { return true; } It doesn't change the semantics. The compiler would recognize it as an intrinsic and would print the message if the clause to its left has failed.There was a proposal a while back to enable CTFE to print messages, which is probably a better solution. msg() could be something along the lines of: bool msg(string) { __ctfeprint(string); return true; } which would involve considerably less compiler magic. Furthermore, `msg` could be a local private function, which would avoid "but I'm already using `msg`" problems.
Jun 11 2017
Walter Bright wrote:On 6/11/2017 8:25 AM, Andrei Alexandrescu wrote:i think, that something like `__constraint(condition, "message")` is ok, and it should be built-in, just like `__traits()`. so compiler can collect those messages, and only show 'em if the matcher is failed to find anything. yeah, another hack in interpreter, but fairly small, and should solve "what constraint is really failed" problem.Ostensibly the function is trivial: bool msg(string) { return true; } It doesn't change the semantics. The compiler would recognize it as an intrinsic and would print the message if the clause to its left has failed.There was a proposal a while back to enable CTFE to print messages, which is probably a better solution. msg() could be something along the lines of: bool msg(string) { __ctfeprint(string); return true; } which would involve considerably less compiler magic. Furthermore, `msg` could be a local private function, which would avoid "but I'm already using `msg`" problems.
Jun 11 2017
On Sunday, 11 June 2017 at 19:51:11 UTC, ketmar wrote:Walter Bright wrote:+1 Implementation wise this one is easiest ... I guess.[...]i think, that something like `__constraint(condition, "message")` is ok, and it should be built-in, just like `__traits()`. so compiler can collect those messages, and only show 'em if the matcher is failed to find anything. yeah, another hack in interpreter, but fairly small, and should solve "what constraint is really failed" problem.
Jun 11 2017
On Sunday, 11 June 2017 at 19:51:11 UTC, ketmar wrote:i think, that something like `__constraint(condition, "message")` is ok, and it should be built-in, just like `__traits()`. so compiler can collect those messages, and only show 'em if the matcher is failed to find anything. yeah, another hack in interpreter, but fairly small, and should solve "what constraint is really failed" problem.This is really nice. I like it better than my suggestion.
Jun 11 2017
On Sunday, 11 June 2017 at 15:25:11 UTC, Andrei Alexandrescu wrote:This would be a very nice change, but this syntax feels more natural to me: is(ReturnType!((R r) => r.empty) == bool, "must support bool empty")// Also possible (no change to the language) enum bool isInputRange(R) = is(typeof((ref R r) => r)) && msg("must be copyable") && is(ReturnType!((R r) => r.empty) == bool) && msg("must support bool empty") && is(typeof(lvalueOf!R.front)) && msg("must support front") && is(typeof(lvalueOf!R.popFront)) && msg("must support back");
Jun 11 2017
On Sunday, 11 June 2017 at 00:28:58 UTC, Andrei Alexandrescu wrote:enum bool isInputRange(R) = is(typeof((ref R r) => r)) && "must be copyable"Regardless of the implementation method, this will require the previously proposed Phobos refactoring. Independent special definitions have to be reduced to general ones and use "static if" to select the algorithm. Otherwise, each failed independent definition will give an additional error message, and the compiler does not have the ability to determine which one is relevant.
Jun 11 2017
On 6/11/2017 12:07 PM, crimaniak wrote:Regardless of the implementation method, this will require the previously proposed Phobos refactoring. Independent special definitions have to be reduced to general ones and use "static if" to select the algorithm. Otherwise, each failed independent definition will give an additional error message, and the compiler does not have the ability to determine which one is relevant.You're right that there are issues with the `msg` thing in the presence of overloading.
Jun 11 2017
On 6/10/2017 5:28 PM, Andrei Alexandrescu wrote:&& is(typeof(lvalueOf!R.popFront)) && msg("must support back");Wouldn't it work better as: && (is(typeof(lvalueOf!R.popFront)) || msg("must support back")); bool msg(string) { return false; } ? Then msg() is only called if the first clause fails.
Jun 11 2017
On Sunday, 11 June 2017 at 19:45:37 UTC, Walter Bright wrote:On 6/10/2017 5:28 PM, Andrei Alexandrescu wrote:I can do a __ctfePrint for string literals. (is(typeof(lvalueOf!R.popFront)) || __ctfePrint("bla")) would work in a short amount of time.&& is(typeof(lvalueOf!R.popFront)) && msg("must support back");Wouldn't it work better as: && (is(typeof(lvalueOf!R.popFront)) || msg("must support back")); bool msg(string) { return false; } ? Then msg() is only called if the first clause fails.
Jun 11 2017
On 6/11/17 3:45 PM, Walter Bright wrote:On 6/10/2017 5:28 PM, Andrei Alexandrescu wrote:The added parens are a small liability. -- Andrei&& is(typeof(lvalueOf!R.popFront)) && msg("must support back");Wouldn't it work better as: && (is(typeof(lvalueOf!R.popFront)) || msg("must support back")); bool msg(string) { return false; } ? Then msg() is only called if the first clause fails.
Jun 11 2017
On Sunday, 11 June 2017 at 00:28:58 UTC, Andrei Alexandrescu wrote:// Also possible (no change to the language) enum bool isInputRange(R) = is(typeof((ref R r) => r)) && msg("must be copyable") && is(ReturnType!((R r) => r.empty) == bool) && msg("must support bool empty") && is(typeof(lvalueOf!R.front)) && msg("must support front") && is(typeof(lvalueOf!R.popFront)) && msg("must support back"); AndreiWhat about using ddoc? enum bool isInputRange(R) = is(typeof((ref R r) => r)) /// must be copyable && is(ReturnType!((R r) => r.empty) == bool) /// must support bool empty && is(typeof(lvalueOf!R.front)) /// must support front && is(typeof(lvalueOf!R.popFront)) /// must support back
Jun 11 2017
On 6/11/17 1:32 PM, Sebastiaan Koppe wrote:What about using ddoc? enum bool isInputRange(R) = is(typeof((ref R r) => r)) /// must be copyable && is(ReturnType!((R r) => r.empty) == bool) /// must support bool empty && is(typeof(lvalueOf!R.front)) /// must support front && is(typeof(lvalueOf!R.popFront)) /// must support backIf there's going to be compiler magic, this seems like a sensible syntax--documenting constraints is a good idea anyway, particularly for those of us who aren't is-expression masters.
Jun 12 2017
On Monday, 12 June 2017 at 17:35:59 UTC, David Gileadi wrote:On 6/11/17 1:32 PM, Sebastiaan Koppe wrote:Yeah, I had meant to mention the compiler magic involved. I suppose the magic is far less than anything else though, since the compiler already associates surrounding docs to code (right?).What about using ddoc? enum bool isInputRange(R) = is(typeof((ref R r) => r)) /// must be copyable && is(ReturnType!((R r) => r.empty) == bool) /// must support bool empty && is(typeof(lvalueOf!R.front)) /// must support front && is(typeof(lvalueOf!R.popFront)) /// must support backIf there's going to be compiler magic, this seems like a sensible syntax--documenting constraints is a good idea anyway, particularly for those of us who aren't is-expression masters.
Jun 12 2017
On Mon, Jun 12, 2017 at 10:35:59AM -0700, David Gileadi via Digitalmars-d wrote:On 6/11/17 1:32 PM, Sebastiaan Koppe wrote:+1, I like this idea much better than any of the others proposed so far. No need for additional syntax, reuse ddoc comment syntax for something that, ostensibly, could be considered documentation. T -- If lightning were to ever strike an orchestra, it'd always hit the conductor first.What about using ddoc? enum bool isInputRange(R) = is(typeof((ref R r) => r)) /// must be copyable && is(ReturnType!((R r) => r.empty) == bool) /// must support bool empty && is(typeof(lvalueOf!R.front)) /// must support front && is(typeof(lvalueOf!R.popFront)) /// must support backIf there's going to be compiler magic, this seems like a sensible syntax--documenting constraints is a good idea anyway, particularly for those of us who aren't is-expression masters.
Jun 12 2017
On Sunday, 11 June 2017 at 00:28:58 UTC, Andrei Alexandrescu wrote:// Also possible (no change to the language) enum bool isInputRange(R) = is(typeof((ref R r) => r)) && msg("must be copyable")Or how about enum bool isInputRange(R) = isCopyable!R && supportsBoolEmpty!R && supportsFront!R && supportsPopFront!R; and the compiler just calls out which condition didn't match?&& is(typeof(lvalueOf!R.popFront)) && msg("must support back");hey look you already messed up the string by repeating it.
Jun 11 2017
On Monday, 12 June 2017 at 00:13:46 UTC, Adam D. Ruppe wrote:On Sunday, 11 June 2017 at 00:28:58 UTC, Andrei Alexandrescu wrote:Much better. Probably could be a bit more generic than that :)// Also possible (no change to the language) enum bool isInputRange(R) = is(typeof((ref R r) => r)) && msg("must be copyable")Or how about enum bool isInputRange(R) = isCopyable!R && supportsBoolEmpty!R && supportsFront!R && supportsPopFront!R; and the compiler just calls out which condition didn't match?Exactly my point. -Steve&& is(typeof(lvalueOf!R.popFront)) && msg("must support back");hey look you already messed up the string by repeating it.
Jun 11 2017
On 6/11/2017 5:13 PM, Adam D. Ruppe wrote:supportsFront!R &&That doesn't work because there may be a local symbol: T front(R r) { } which will not be in scope in supportsFront().
Jun 12 2017
On Monday, 12 June 2017 at 07:18:30 UTC, Walter Bright wrote:On 6/11/2017 5:13 PM, Adam D. Ruppe wrote:That is a problem regardless of the constraint. Even if we are clever enough to construct the constraint to workaround this issue, code that uses such ranges will not compile. -StevesupportsFront!R &&That doesn't work because there may be a local symbol: T front(R r) { } which will not be in scope in supportsFront().
Jun 12 2017
On 06/12/2017 03:18 AM, Walter Bright wrote:On 6/11/2017 5:13 PM, Adam D. Ruppe wrote:Yah, this was part of the original design: migrate all checks to std.traits. At a point I realized that queries of the form "does a.b work?" need to be accompanied by passing a number of modules to import in order to resolve possible UFCS for "b". At the moment I had a standard library artifact import a user-defined module, I decided things got too odd and gave up on that. -- AndreisupportsFront!R &&That doesn't work because there may be a local symbol: T front(R r) { } which will not be in scope in supportsFront().
Jun 12 2017