www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why opDispatch uses SFINAE implicitly?

reply Dukc <ajieskola gmail.com> writes:
If I define an opDispatch for something, but the call does not 
compile, the compiler currently behaves as if the opDispatch 
didn't exist at all. Just like C++ templates as  far as I know. 
Why is this? I think it would be better if it acted like other D 
templates: Compilation failure is always an error, but you can 
use preconditions if you want the "substitution failure is not an 
error"-idiom. This would be better to detect errors.

Is there any way to define a dispatching type so that it errs or 
at least announces if the call does not compile?
Mar 01
next sibling parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Thursday, 2 March 2017 at 06:40:29 UTC, Dukc wrote:
 If I define an opDispatch for something, but the call does not 
 compile, the compiler currently behaves as if the opDispatch 
 didn't exist at all. Just like C++ templates as  far as I know. 
 Why is this? I think it would be better if it acted like other 
 D templates: Compilation failure is always an error, but you 
 can use preconditions if you want the "substitution failure is 
 not an error"-idiom. This would be better to detect errors.

 Is there any way to define a dispatching type so that it errs 
 or at least announces if the call does not compile?
All templates have SFINAE. opDispatch as well. you can force a compilation error by defining a catch-all overload that static asserts.
Mar 02
parent reply Dukc <ajieskola gmail.com> writes:
On Thursday, 2 March 2017 at 08:01:48 UTC, Stefan Koch wrote:
 All templates have SFINAE.
They do, by default? Gotta test that when I return home...
Mar 02
parent reply Dukc <ajieskola gmail.com> writes:
On Thursday, 2 March 2017 at 08:37:40 UTC, Dukc wrote:
 All templates have SFINAE.
No, they don't: import std.stdio; void main() { printType!uint("the type is: "); } void printType(T)(string precedent) { writeln(precedent ~ T.stringof); } //the type is: uint void main() { printType!uint("the type is: "); } void printType(T)(string precedent) { writeln(precedent ~ T.stringOf); } // Error: no property 'stringOf' for type 'uint' // Error: template instance app.printType!uint error instantiating void main() { printType!uint("the type is: "); } void printType(T)(string precedent) { writeln(precedent ~ T.stringof); } void printType(T)(string precedent) { writeln(precedent ~ T.stringOf); } //Error: app.printType called with argument types (string) matches both: [snip] If D templates had SFINAE as I understand it, the third one would compile. I am not 100% sure if C++ would work that way, but at least opDispatch seems to. If it does not compile, compiler to look for regular templates and announces "no match" as if there were no implementation at all. But for a regular template implemented in just the same way it would print what in the implementation did not compile. That's what I'm missing with opDispatch. I still have to test if I can get that catch-all error-printing opDispatch to work...
Mar 02
parent Dukc <ajieskola gmail.com> writes:
On Thursday, 2 March 2017 at 12:05:44 UTC, Dukc wrote:
 I still have to test if I can get that catch-all error-printing 
 opDispatch to work...
I encountered a problem: it was not SFINAE after all. If the compiler detects two canditates it won't try to use either of them, it just silently ignores opDispatchs again. auto ref opDispatch(string Op, Args...)(Args arguments) { static if(is(typeof(_opDispatch!Op(arguments)))) _opDispatch!Op(arguments); else { import std.conv; pragma(msg, "opDispatch didn't compile at " ~ __FILE__ ~ " " ~ __LINE__.to!string ); assert(false); } } This works, but is annoying to use: -It is clunky to define. Could be of course made better with a mixin. -It does not abort compilation. If I use a static (dis)assert, that's a compilation error which again causes ignorance of the whole implementation. -You have to manually replace the call dispatched with a direct _opDispatch call and recompile to get the real error behind. But is it the best option?
Mar 02
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 2 March 2017 at 06:40:29 UTC, Dukc wrote:
 If I define an opDispatch for something, but the call does not 
 compile, the compiler currently behaves as if the opDispatch 
 didn't exist at all.
I think this is actually an accident of implementation, because when it was new, it actually did error out, but then it wouldn't check other things like alias this. So they fixed one bug, but introduced this.... It is really annoying, even a typo inside opDispatch can cause it to fail to compile and just be removed from consideration. At the call point, if you get "no such property" when you expected opDispatch, you can rewrite it manually to `obj.opDispatch!"name"`, recompile, and see the actual error. But otherwise, I don't know of any trick to get it. I call it a compiler error message bug. (we're starting to have a LOT of them)
Mar 02
parent Dukc <ajieskola gmail.com> writes:
On Thursday, 2 March 2017 at 18:17:05 UTC, Adam D. Ruppe wrote:
 But otherwise, I don't know of any trick to get it. I call it a 
 compiler error message bug. (we're starting to have a LOT of 
 them)
Well, look my last post if you didn't already. That does not fix the problem, but at least makes the compiler announce when this happens. But Í'm glad if it's a bug, not a feature. Thanks for the explanation.
Mar 02