Thread overview
Why opDispatch uses SFINAE implicitly?
Mar 02, 2017
Dukc
Mar 02, 2017
Stefan Koch
Mar 02, 2017
Dukc
Mar 02, 2017
Dukc
Mar 02, 2017
Dukc
Mar 02, 2017
Adam D. Ruppe
Mar 02, 2017
Dukc
March 02, 2017
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?
March 02, 2017
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.
March 02, 2017
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...


March 02, 2017
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...
March 02, 2017
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?
March 02, 2017
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)
March 02, 2017
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.