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

Why can't compiler resolve type in a generic method for a non-generic callee? #8273

Closed
ghost opened this issue Feb 1, 2016 · 3 comments
Closed

Comments

@ghost
Copy link

ghost commented Feb 1, 2016

In C++, following code is legit:

static void A(char ch) { }

template<typename S>
static void B(S txt) {
    A(txt);
}

int main() {
    char x = 'x';
    B(x);
}

In C#, the generics don't allow this:

static void A(char ch) { }

static void B<S>(S txt) {
    A(txt);  // error CS1503: Cannot convert from 'S' to 'char'
}

static void Main(string[] args) {
    char x = 'x';
    B(x);
}

Why can't compiler resolve it, when there is only one caller, one generic dispatcher and one implicit callee?

Can't generic borrow this feature from C++ templates?

Any chance this can turn into a viable proposal?

@Suchiman
Copy link
Contributor

Suchiman commented Feb 1, 2016

In C++ this works because templates are effectively copy-specialized ahead of time for each caller. So it copies the template, substitutes the placeholders and if it compiles, it compiles.

In C# generics are metadata driven. The compiler embeds the method generically into the assembly without specializing for any caller. Specialization is done at runtime by the JIT, but as you've already figured, you're reciving the error at compile time, because it's not caller specialized and the compiler can't express the idea of "this method is only called once and when it is, it has the correct type, so it's declared generic but really isn't" in metadata.

This also wouldn't be very intuitive, compiler errors caused in method bodies by the caller...

@dsaf
Copy link

dsaf commented Feb 1, 2016

Why can't compiler resolve it, when there is only one caller, one generic dispatcher and one implicit callee?
Can't generic borrow this feature from C++ templates?

https://msdn.microsoft.com/en-us/library/c6cyy67b.aspx

C++ allows code that might not be valid for all type parameters in the template, which is then checked for the specific type used as the type parameter. C# requires code in a class to be written in such a way that it will work with any type that satisfies the constraints.

http://stackoverflow.com/questions/1208153/c-sharp-generics-compared-to-c-templates

http://stackoverflow.com/questions/740969/c-sharp-generics-vs-c-templates-need-a-clarification-about-constraints

http://stackoverflow.com/questions/15857544/what-are-the-differences-between-c-templates-and-java-c-generics-and-what-are

Any chance this can turn into a viable proposal?

Yes #1911 but C++ is not the best source of inspiration for this.

Something usable in .NET today: https://github.com/rsdn/nemerle/wiki/Macros-tutorial
A well-designed fringe language: https://doc.rust-lang.org/book/macros.html

@jaredpar
Copy link
Member

jaredpar commented Feb 2, 2016

Can't generic borrow this feature from C++ templates?

No because this comes down to a fundamental difference between generics and templates.

  • Generics: Every method, property, etc ... must be 100% type safe on it's own for all possible instantiations of the type arguments. This is a requirement in both C# and the underlying metadata.
  • Templates: In order for a template to be a valid C++ member it simply needs to parse correctly. No type safety checks occur at the definition. Instead they occur when a C++ template member is instantiated with a given type.

The closest analogous features to C++ templates in C# is the proposal of introducing structural typing. This is something I'd love to see us do one day but it's a rather big work item.

@jaredpar jaredpar closed this as completed Feb 2, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants