Thread overview | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 25, 2014 Showing a user specified error message when no overloads match | ||||
---|---|---|---|---|
| ||||
I have a template function with a particular constraint (in this case [1]). When this constraint doesn't match, I want to give the user a suggestion what to do instead. The only way I know of to do this currently is to relax the template constraints, and adding a `static assert`. However, if there is another function that would match, this would lead to an ambiguity. Is there a way to trigger the static assert only if there are no other overloads (including members and UFCS functions) that match? Or maybe a solution that only works for this particular case? [1] https://github.com/D-Programming-Language/phobos/pull/2350 |
July 26, 2014 Re: Showing a user specified error message when no overloads match | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | Yeah that's the price we pay for the simplicity. Also most constraints directly or indirectly consist of a complex boolean expressions and you don't get any hint which part failed and why. |
July 26, 2014 Re: Showing a user specified error message when no overloads match | ||||
---|---|---|---|---|
| ||||
Posted in reply to Trass3r | Hmmm... thinking about it, is this possible? 1. Remove the constraints to match anything. 2. Inside the template, have some construct that enumerates all possible overloads and UFCS functions that are visible at the point of instantiation. 3. If this set contains only the current template, use a static assert to print the message. 4. Otherwise, make the template fail to compile somehow (for example, evaluate a semantically invalid expression), and hope that the compiler will then take the other overloads into consideration (SFINAE). Could this work? |
July 27, 2014 Re: Showing a user specified error message when no overloads match | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On Sat, Jul 26, 2014 at 05:14:44PM +0000, via Digitalmars-d-learn wrote: > Hmmm... thinking about it, is this possible? > > 1. Remove the constraints to match anything. > 2. Inside the template, have some construct that enumerates all possible > overloads and UFCS functions that are visible at the point of instantiation. > 3. If this set contains only the current template, use a static assert > to print the message. > 4. Otherwise, make the template fail to compile somehow (for example, > evaluate a semantically invalid expression), and hope that the > compiler will then take the other overloads into consideration > (SFINAE). > > Could this work? D does not have SFINAE. This has been discussed before. I proposed the following solution: - Sig constraints should match all types that the function *logically* accepts -- even if the current implementation does not support some of said types. - In the function body, use a `static if` chain to implement specializations. - In the final else clause, do a static assert(0) with a user-friendly error message. T -- In order to understand recursion you must first understand recursion. |
July 27, 2014 Re: Showing a user specified error message when no overloads match | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Sunday, 27 July 2014 at 00:43:40 UTC, H. S. Teoh via Digitalmars-d-learn wrote: > On Sat, Jul 26, 2014 at 05:14:44PM +0000, via Digitalmars-d-learn wrote: >> Hmmm... thinking about it, is this possible? >> >> 1. Remove the constraints to match anything. >> 2. Inside the template, have some construct that enumerates all possible >> overloads and UFCS functions that are visible at the point of instantiation. >> 3. If this set contains only the current template, use a static assert >> to print the message. >> 4. Otherwise, make the template fail to compile somehow (for example, >> evaluate a semantically invalid expression), and hope that the >> compiler will then take the other overloads into consideration >> (SFINAE). >> >> Could this work? > > D does not have SFINAE. http://dlang.org/templates-revisited.html says otherwise. But thinking about it, I've never seen it used anywhere, nor used it myself, and even the examples in the linked article under the SFINAE section use `is` expressions instead... > > This has been discussed before. I proposed the following solution: > > - Sig constraints should match all types that the function *logically* > accepts -- even if the current implementation does not support some of > said types. > > - In the function body, use a `static if` chain to implement > specializations. > > - In the final else clause, do a static assert(0) with a user-friendly > error message. But this prevents other people from providing overloads in their own modules :-( |
July 27, 2014 Re: Showing a user specified error message when no overloads match | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On Sunday, 27 July 2014 at 08:40:42 UTC, Marc Schütz wrote: > On Sunday, 27 July 2014 at 00:43:40 UTC, H. S. Teoh via Digitalmars-d-learn wrote: >> On Sat, Jul 26, 2014 at 05:14:44PM +0000, via Digitalmars-d-learn wrote: >>> Hmmm... thinking about it, is this possible? >>> >>> 1. Remove the constraints to match anything. >>> 2. Inside the template, have some construct that enumerates all possible >>> overloads and UFCS functions that are visible at the point of instantiation. >>> 3. If this set contains only the current template, use a static assert >>> to print the message. >>> 4. Otherwise, make the template fail to compile somehow (for example, >>> evaluate a semantically invalid expression), and hope that the >>> compiler will then take the other overloads into consideration >>> (SFINAE). >>> >>> Could this work? >> >> D does not have SFINAE. > > http://dlang.org/templates-revisited.html says otherwise. > > But thinking about it, I've never seen it used anywhere, nor used it myself, and even the examples in the linked article under the SFINAE section use `is` expressions instead... It's poorly worded: "is" is what functionally replaces the SFINAE functionality. >> >> This has been discussed before. I proposed the following solution: >> >> - Sig constraints should match all types that the function *logically* >> accepts -- even if the current implementation does not support some of >> said types. >> >> - In the function body, use a `static if` chain to implement >> specializations. >> >> - In the final else clause, do a static assert(0) with a user-friendly >> error message. > > But this prevents other people from providing overloads in their own modules :-( Not quite: It prevents users from providing "un-ambigous" overloads. But arguably, it's a good thing. I've argued before against the "over use" of template constraints for type validation. Their initial use was really to restrict the "logical types" that can be used, and help with template overload. Not for validation. If the type then has some "flaw", that's where the static ifs come in. This as a several advantages: - Cleaner interface (*cough* http://dlang.org/phobos/std_algorithm.html#sort *cough*) - Better error messages in case of non match ("The provided range can not be stable sorted, because its elements are not lvalues"). - Prevents "overload" turning into a hijack. You can add your overload (without ambiguity) if it works on types completely un-related. That won't be ambiguous. But if you are adding a very specific variant, it might be better that your function can't be accidentally called, and create surprises later. |
July 29, 2014 Re: Showing a user specified error message when no overloads match | ||||
---|---|---|---|---|
| ||||
Posted in reply to monarch_dodra | opDispatch behaves as though it has SFINAE. When something fails in the definition (like I am having now, some of the symbols I used in it hadn't been imported) there won't ever be an error message, I just get "Error: no property 'bar' for type 'Foo'" In one case I had to use static ifs and pragmas and static assert(0) to get error messages out of opDispatch because static assert messages were being suppressed. Its very frustrating. |
July 29, 2014 Re: Showing a user specified error message when no overloads match | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vlad Levenfeld | On Tue, Jul 29, 2014 at 03:34:22AM +0000, Vlad Levenfeld via Digitalmars-d-learn wrote: > opDispatch behaves as though it has SFINAE. When something fails in the definition (like I am having now, some of the symbols I used in it hadn't been imported) there won't ever be an error message, I just get "Error: no property 'bar' for type 'Foo'" > > In one case I had to use static ifs and pragmas and static assert(0) to get error messages out of opDispatch because static assert messages were being suppressed. > > Its very frustrating. You're right, opDispatch behaves like SFINAE. I've had trouble debugging it before, because when it works, it works very well, but when you accidentally make a typo, it just "disappears" -- you get an error that the property is missing, but the actual error inside opDispatch has been gagged and it's almost impossible to get at the actual error message. Maybe we should file an enhancement bug to improve error reporting for opDispatch. T -- Time flies like an arrow. Fruit flies like a banana. |
July 29, 2014 Re: Showing a user specified error message when no overloads match | ||||
---|---|---|---|---|
| ||||
On 07/29/14 17:45, H. S. Teoh via Digitalmars-d-learn wrote:
> You're right, opDispatch behaves like SFINAE. I've had trouble debugging it before, because when it works, it works very well, but when you accidentally make a typo, it just "disappears" -- you get an error that the property is missing, but the actual error inside opDispatch has been gagged and it's almost impossible to get at the actual error message.
D's overloaded operators are (usually) normal (templated) functions, you
can use `a.opDispatch!"blah"` instead of `a.blah` to see what's wrong.
What's really nasty is the way phobos handles `toString` - if that method fails to compile then you get a usually not very helpful default, and no warning that something is wrong. It's easy to break `toString` w/o noticing anything. Figuring out later what exactly broke can be "interesting". Still doable via the above mentioned trick, but you'll need to create a mock `sink` etc.
artur
|
July 29, 2014 Re: Showing a user specified error message when no overloads match | ||||
---|---|---|---|---|
| ||||
On Tue, Jul 29, 2014 at 06:57:00PM +0200, Artur Skawina via Digitalmars-d-learn wrote: > On 07/29/14 17:45, H. S. Teoh via Digitalmars-d-learn wrote: > > You're right, opDispatch behaves like SFINAE. I've had trouble debugging it before, because when it works, it works very well, but when you accidentally make a typo, it just "disappears" -- you get an error that the property is missing, but the actual error inside opDispatch has been gagged and it's almost impossible to get at the actual error message. > > D's overloaded operators are (usually) normal (templated) functions, > you can use `a.opDispatch!"blah"` instead of `a.blah` to see what's > wrong. Good idea! Though it's still limited when the opDispatch call is buried under several layers of templated generic functions. The problem is, sometimes you don't even know that the problem is inside opDispatch because failure causes it to default to something else (that generates an unrelated error message), and the actual error message is gagged. Then once you do narrow it down, it isn't always so easy to get at the code that calls opDispatch, since it could be quite deep inside generic functions. Once you pinpoint it, though, your idea is pretty good -- invoke it directly so that the errors are not gagged. > What's really nasty is the way phobos handles `toString` - if that method fails to compile then you get a usually not very helpful default, and no warning that something is wrong. It's easy to break `toString` w/o noticing anything. Figuring out later what exactly broke can be "interesting". Still doable via the above mentioned trick, but you'll need to create a mock `sink` etc. [...] Mock sinks are very easy, because a delegate is a sink. :-) import std.range; int delegate(const(char)[]) dg; static assert(isOutputRange!(typeof(dg), const(char)[])); // passes Which makes it very handy to insert arbitrary debugging code for toString via dg.formattedWrite("%s", obj). T -- "I'm running Windows '98." "Yes." "My computer isn't working now." "Yes, you already said that." -- User-Friendly |
Copyright © 1999-2021 by the D Language Foundation