-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Proposal: Infer generic type based on target #5429
Comments
Is it really that much easier/neater to write the first line instead of the second? LocationComponent loс = entity.Get();
//vs
var loc = entity.Get<LocationComponent>(); I personally feel betrayed by the compiler every time I have to write the type of a local instead of using |
Additional use case in properties and/or methods based on return type: // calls fields.Get<int>("Id") utilizing CallerMemberNameAttribute
public int Id => fields.Get(); |
In that scenario it's definitely not an improvement. I'm thinking specifically of scenarios where the target is already defined, whether it be an existing variable or a property. The inspiration for this is in the proposal itself, someone I work with complaining about having to explicitly specify the generic type argument when calling the |
What if there is a non-generic overload of the new Something
{
Id = row.Field<>("id"),
ObjValue = row.Field("obj")
} |
I think this proposal could make a good impact when using mocking frameworks such as NSubstitute and FakeItEasy: A.CallTo(() => foo.Bar("hello", A<int>.Ignored)).MustHaveHappened();
calculator.Add(Arg.Any<int>(), 5).Returns(7); vs A.CallTo(() => foo.Bar("hello", A.Ignored)).MustHaveHappened();
calculator.Add(Arg.Any(), 5).Returns(7); |
Also for
|
I marked this as "Need More Info", as we'd like you to suggest what modifications to the type inference specification you'd like to see to address this. |
I'll try to do my best to hammer that out. I don't think I've seen any examples in the spec of type inference occurring in this direction so I don't know how well it can be accomplished through minor updates to the spec. Spec-writing is far from my strong-suit so please be patient with me. 😁 Under §7.5.2:
The use of the assignment operator is only to indicate that the assignment of the return value is to play a part in the type inference. That may not be the best syntax but the goal is to indicate that as long as the type of the target of the assignment is known that it can be used for type inference. The simplest scenario would be when the return value is being assigned to an explicitly typed variable, field or property. Expanding that to method arguments would be ideal but I can see situations where that would result in circular inference. Under §7.5.2.1:
I'm not sure changes to the other section would apply as I don't intend to alter how existing type inference works, only apply the target type in the cases where current inference would fail. For example: // given:
T M1<T>(T x1) { ... };
T M2<T>(params T[] x) { ... }
TR M3<T, TR>(T x) { ... }
// infers M1<string>, compiler error
int x1 = M1("foo");
// infers M2<int>
int x2 = M2();
// infers M2<string>, compiler error
int x3 = M2("foo");
// infers M3<string, int>
int x4 = M3("foo"); |
My 2 cents. I don't think this should be all about assignments, however. Consider the following example:
The above code should infer T based on the return type expected during static overload resolve. If there would have been two overloads of Method(), then the compiler should have issued an ambiguous match exception. What I mean is: generic parameters should be inferred based on return type as they are now inferred based on parameter types. If T is used as a return type only, it should use "the type expected by the parent expression" to infer T. And this includes: assignment (type of a field, property or a local variable), returning a value (return type of a current method or property), calling a method (if and only if this parameter has the same type in all of the overloads). |
I agree, I'd treat assignment to an argument of a method call the same as I would an assignment to a property or a variable. My only concern is that methods open up a can of worms as the generic type inference will have to deal with overloads and generic method calls as well. The easy answer there would be to fail inference if there is any potential ambiguity like that. This is what Java does. But Java doesn't have to deal with inference in both directions. |
Somehow unrelated but I wonder why this can't be inferred, void M(object o) {}
void F<T>(Action<T> a) {}
F((object o) => {}); // fine
F(M); // nope Is there a specific reason? EDIT: Probably because |
We are now taking language feature discussion in other repositories:
Features that are under active design or development, or which are "championed" by someone on the language design team, have already been moved either as issues or as checked-in design documents. For example, the proposal in this repo "Proposal: Partial interface implementation a.k.a. Traits" (issue 16139 and a few other issues that request the same thing) are now tracked by the language team at issue 52 in https://github.com/dotnet/csharplang/issues, and there is a draft spec at https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md and further discussion at issue 288 in https://github.com/dotnet/csharplang/issues. Prototyping of the compiler portion of language features is still tracked here; see, for example, https://github.com/dotnet/roslyn/tree/features/DefaultInterfaceImplementation and issue 17952. In order to facilitate that transition, we have started closing language design discussions from the roslyn repo with a note briefly explaining why. When we are aware of an existing discussion for the feature already in the new repo, we are adding a link to that. But we're not adding new issues to the new repos for existing discussions in this repo that the language design team does not currently envision taking on. Our intent is to eventually close the language design issues in the Roslyn repo and encourage discussion in one of the new repos instead. Our intent is not to shut down discussion on language design - you can still continue discussion on the closed issues if you want - but rather we would like to encourage people to move discussion to where we are more likely to be paying attention (the new repo), or to abandon discussions that are no longer of interest to you. If you happen to notice that one of the closed issues has a relevant issue in the new repo, and we have not added a link to the new issue, we would appreciate you providing a link from the old to the new discussion. That way people who are still interested in the discussion can start paying attention to the new issue. Also, we'd welcome any ideas you might have on how we could better manage the transition. Comments and discussion about closing and/or moving issues should be directed to #18002. Comments and discussion about this issue can take place here or on an issue in the relevant repo. I am not moving this particular issue because I don't have confidence that the LDM would likely consider doing this. The way the language specification (and therefore compiler) is structured, the type of the target of the assignment of an invocation isn't available when type inference is performed. Target typing in C# works in a completely different way than imagined by this request. |
Discussion can continue at dotnet/csharplang#92 . |
Problem
When calling generic methods where the generic type parameter is only used as the return value of the method there is currently no inference which leads to repetition.
Proposal
It would be convenient if in the specific case of the generic type parameter being the return type if the compiler could infer the generic type argument based on the destination of the result. This would only be permitted if the method is called in an unambiguous fashion. The return value must be assigned to a destination with an explicit type and there can be no other non-generic methods with the same name and parameters.
The text was updated successfully, but these errors were encountered: