Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

isCallable fails for template opCall overload #9780

Open
dlangBugzillaToGithub opened this issue Sep 26, 2019 · 7 comments
Open

isCallable fails for template opCall overload #9780

dlangBugzillaToGithub opened this issue Sep 26, 2019 · 7 comments
Labels
OS:Linux Issues specific to Linux Severity:Normal

Comments

@dlangBugzillaToGithub
Copy link

snarwin+bugzilla (@pbackus) reported this on 2019-09-26T18:50:31Z

Transfered from https://issues.dlang.org/show_bug.cgi?id=20246

CC List

  • maxsamukha
  • simen.kjaras
  • zan77137

Description

import std.traits: isCallable;

struct S { int opCall(T)(T) { return 0; } }

static assert(isCallable!(S.init));

---

The above static assert should pass, but instead fails.
@dlangBugzillaToGithub
Copy link
Author

simen.kjaras commented on 2019-09-27T06:34:43Z

It's impossible to distinguish between the above case and this:

struct S { enum opCall(T) = true; }

Clearly, the latter is *not* callable.

To illustrate the situation perhaps more clearly:

struct S {
    template opCall(T) {
        static if (is(T == int)) {
            void opCall(T t) {}
        } else {
            enum opCall = 14;
        }
    }
}

The above is perfectly valid code, but should isCallable!S return true?

@dlangBugzillaToGithub
Copy link
Author

snarwin+bugzilla commented on 2019-09-27T15:35:26Z

Seems like this is an issue with the interface, then, not the implementation; the question "is S.init callable" is undecidable, so there's not much use trying to pretend we can answer it.

One possible solution would be a trait like `isCallableWith!(S.init, int)`, that requires the user to specify the argument type(s). That way, we could just check with __traits(compiles) whether the call is valid or not.

@dlangBugzillaToGithub
Copy link
Author

maxsamukha commented on 2019-09-28T06:27:27Z

(In reply to Paul Backus from comment #2)

> One possible solution would be a trait like `isCallableWith!(S.init, int)`,
> that requires the user to specify the argument type(s). That way, we could
> just check with __traits(compiles) whether the call is valid or not.

That does not take into account rvalue-ness of the arguments:

void foo(ref int) {}
store
static if (isCallableWith!(typeof(1)))
    foo(1); // error

isCallableWith would have to accept the actual arguments, (type, rvalue-ness) pairs, or both.

And if one implements isCallableWith for functions, he should also implement isInstantiatableWith for templates. And that is a case for general __traits(matchFunction/matchTemplate, symbol, args) that would return the overloads callable/instantiatable with args. isCallableWith/isInstantiatableWith could be built on that.

@dlangBugzillaToGithub
Copy link
Author

maxsamukha commented on 2019-09-28T06:29:30Z

(In reply to Max Samukha from comment #3)

> isCallableWith!(typeof(1))

Typo: isCallableWith!(foo, typeof(1))

@dlangBugzillaToGithub
Copy link
Author

snarwin+bugzilla commented on 2019-09-28T15:30:04Z

(In reply to Max Samukha from comment #3)
> That does not take into account rvalue-ness of the arguments:
> 
> void foo(ref int) {}
> store
> static if (isCallableWith!(typeof(1)))
>     foo(1); // error
> 
> isCallableWith would have to accept the actual arguments, (type,
> rvalue-ness) pairs, or both.

Then perhaps the best solution is to add a note to the documentation of isCallable highlighting its shortcomings, and encourage everyone to instead use __traits(compiles) directly with the actual function call they want to make.

@dlangBugzillaToGithub
Copy link
Author

simen.kjaras commented on 2020-08-10T07:26:58Z

*** Issue 21137 has been marked as a duplicate of this issue. ***

@dlangBugzillaToGithub
Copy link
Author

simen.kjaras commented on 2020-08-10T07:40:37Z

It's impossible to solve this in the general case, and even the special cases can't be solved in library code, but a __traits could check if the only member of the template is a callable (potentially also if all possible members would be callables).

@LightBender LightBender removed the P3 label Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OS:Linux Issues specific to Linux Severity:Normal
Projects
None yet
Development

No branches or pull requests

2 participants