Replies: 11 comments
-
I second that, interfaces should be out of type inference procedure. |
Beta Was this translation helpful? Give feedback.
-
Absolutely disagree with those arguing against inferring a common interface type. From my perspective, this feature would be useless without supporting the case of types sharing a single interface:
|
Beta Was this translation helpful? Give feedback.
-
Except if intersection types (#228) are implemented. |
Beta Was this translation helpful? Give feedback.
-
edit I see my example was brougth up before. With the same conclusion: implementing this has too many disadvantages, at least until intersect types are supported. If you implement this feature supporting interfaces, you lose the ability to add interfaces without breaking code. Up to framework version 4 this would probably evaluate to an
In framework version 4.5, the On the other hand, if you implement this feature supporting only base classes, you lose much of the usefulness and the ability to replace an abstract base class with an interface. I think in both cases, the price is too high. So you just need to explicitly cast:
However, I do still think this should evaluate to a nullable:
even though this can often be circumvented by null coalescing:
|
Beta Was this translation helpful? Give feedback.
-
This is an argument for this feature, right? Having mutable collections implement However, leaving that aside, you appear to be saying that this proposal should be restricted to what's already covered by the nullable-enhanced common type proposal, which effectively renders this proposal, a duplicate one. |
Beta Was this translation helpful? Give feedback.
-
@DavidArno IReadOnlyList is of course trying to fix mistakes made in the past without breaking existing code. If downward compatibility wasn't necessary, you would have two interfaces: IList and IMutableList. IList would naturally be readonly, and the IsReadOnly property wouldn't be necessary. |
Beta Was this translation helpful? Give feedback.
-
Everyone has accepted the API artifact that |
Beta Was this translation helpful? Give feedback.
-
Hmm, yet again I find myself outside the set of "Everyone". In my world, the proper names for those misnamed interfaces are:
I mentally translate them as "collection == countable enumeration" and "list == indexable enumeration" to work out which to use. |
Beta Was this translation helpful? Give feedback.
-
Als long as we all agree that creating an "IsReadOnly" property indicating if it's legal to call "Add" or "Remove" wasn't an anward winning design decision, and that the decision to finally create an interface indicating you can enumerate and index a collection is a better one. :-) |
Beta Was this translation helpful? Give feedback.
-
@DavidArno None of us disagrees with you there. What you're saying is perpendicular to my point. You yourself are fluent enough in BCLspeak to recognize that |
Beta Was this translation helpful? Give feedback.
-
This expression: x.Count != 0 && y.Count != 0 ? new SomeClassWhichRequiresBothXItemsAndYItems(x, y) :
x.Count == 0 && y.Count == 0 ? null :
throw new SomeException("...") Gives:
This is the workaround but it feels like an unjustified arbitrary requirement, just like x.Count != 0 && y.Count != 0 ? new SomeClassWhichRequiresBothXItemsAndYItems(x, y) :
x.Count == 0 && y.Count == 0 ? (SomeClassWhichRequiresBothXItemsAndYItems)null :
throw new SomeException("...") Why couldn't we assume the type of the inner ternary expression is Should I start a new issue for this? |
Beta Was this translation helpful? Give feedback.
-
@dsaf commented on Fri Mar 20 2015
This code will currently not work:
It could go one step further and assume the first common type in the inheritance hierarchy.
Several situations possible:
Related SO question: http://stackoverflow.com/questions/2799902/implicit-typing-of-arrays-that-implement-interfaces.
@gafter commented on Fri Mar 20 2015
As I understand it, you are requesting a modification to the best common type of a set of expressions specification (C# language spec section 7.5.2.14).
@svick commented on Fri Mar 20 2015
It looks to me like you have two proposals:
The two seem to be completely independent to me, so I think they should have separate issues.
@dsaf commented on Sat Mar 21 2015
@gafter : yes, but maybe more like @svick 's post above? Do I need to create a separate issue for (2)?
@gafter commented on Sat Mar 21 2015
@dsaf Yes, a separate issue would be a good idea, please.
@zippec commented on Fri Jul 24 2015
I'd rather not see this feature implemented.
This problem often occurs in Scala when you make a mistake in decalration, usualy the top class is inferred. The declaration itself is then valid, but errors start popping from all around the code.
Current C# inference is the perfect mix of power and clarity, don't change it please.
@dsaf commented on Fri Jul 24 2015
@jveselka
Well, yes this is the most straightforward assumption to make. If you create a list of an apple a banana and an orange than most likely you want a list of fruit. This is what I would personally expect and Scala seems to be confirming it for me.
var
- it can be aList<>
or anIEnumerable<>
or anIQueryable<>
depending on the last method in the chain. The IDE guides you to fix the problem in seconds. It's already there, it's what people are doing, it works.var
to see the inferred type and adjust the code if needed.I cannot see how what you have described could be a problem. Can you please give a sample of the situation and code?
@zippec commented on Fri Jul 24 2015
@dsaf
Imagine you have this code:
Then you try to add Tomato forgeting that it is technically a Fruit
So error that should have appeared at declaration appears further in the code as different error.
I can even imagine cases where similar mistake results in runtime error and I fear some developers will rather fall back to using explicitly typed locals rather than dealing with these problems.
@dsaf commented on Sun Jul 26 2015
@jveselka I see your point and it's a valid concern. There could be ways a modern IDE would circumvent this (e.g. showing a warning 'Suspicious best type inferred - object' together with the error you have given as an example). This issue needs more opinions.
@dsaf commented on Thu Sep 10 2015
Related to #438.
@HaloFour commented on Thu Sep 10 2015
Not to mention how to determine what that best type is. Do you go up three levels of hierarchy to find a common base class, or two to find a common implemented interface? I think that there are too many questions and concerns to start having the compiler guess. I don't think that type inference should do much more than be a simple convenience so that the developer can type less in those cases where there is no possible ambiguity, but as soon as the intent isn't absolutely crystal-clear the developer should be required to explicitly state their intent through declaration. Not to mention, I'm going to have to be able to read that same code again at some point in the future and I don't want to have to make the same best guess that the compiler will have to.
@paul1956 commented on Thu Sep 10 2015
If you are worried about typing and reading code in the future why not offer a automatic "make explicit mode" and compile with "Strict On". It solves both issues you raise. Whenever you type
The IDE replaces it with
@gafter commented on Thu Sep 10 2015
@paul1956 C# doesn't have a
Dim
keyword.@paul1956 commented on Thu Sep 10 2015
@gafter My example was VB but the concept applies.to both languages.
@gafter commented on Thu Sep 10 2015
@paul1956 The languages are different enough that your suggestion could be interpreted to mean one of a number of things in the context of C#.
@paul1956 commented on Thu Sep 10 2015
I don't know C# well enough to construct examples. The concept is once I finish typing the statement the IDE goes back and adds the missing "Type" information. In VB's case the "As integer", this gets more interesting when the Type is IEnumerable(Of INamedTypeSymbol).. Today at least for VB there are Code Refactoring's to do it but they require more keystrokes.
@gafter commented on Thu Sep 10 2015
Why doesn't C# already do this
There was an explicit decision to have the C# compiler, in type inference, only produce types that were input to the inference process. The reason is that expanding the type inference to other types can result in very complex and nonintuitive results. See, for example, a stackoverflow question about infinite types in Java that result from type inference. It is all well and good to say that we should generalize the common-supertype computation, but actually doing so in practice - in a way that is intuitive to users - is very hard. We would need a specific concrete proposal (not just a list of options) along with a prototype to play with in order to move this kind of proposal forward. If the proposal includes special cases like "if there happens to be only a single common interface..." then it is unlikely to be seen as a good solution, as it will be fragile in the face of adding an interface to an existing class - a kind of fragility we like to avoid. I suspect any solution would require adding the concept of intersection types ala Java.
Any solution for C# would likely be applied equally to VB, so we're treating this issue as covering both languages.
@gafter commented on Thu Sep 10 2015
@paul1956 A refactoring might help to convert correct code into more explicit correct code. But in this code the original code won't typecheck, so the compiler can't select an appropriate type for the variable.
Generally, C# programmers prefer not to have refactorings and code normalization (other than whitespace) applied automatically.
@paul1956 commented on Thu Sep 10 2015
I was responding to the comment by @HaloFour where he said he didn't want to guess what the compiler did. Maybe I should open a new issue and move my comments to a VB thread. I am sensitive to this issue because I just spend the last 3 days refactoring someone else's code to add type information and the bug I was chasing was only found when a String was changed to its correct Type Integer. I found existing refactoring extensions to be very slow and in many cases inaccurate.
@alrz commented on Thu Dec 31 2015
@gafter Does this apply numeric promotions for integrals or implicit type conversions for other types?
@gafter commented on Thu Dec 31 2015
@alrz It doesn't have a design or implementation, so it doesn't do anything yet.
@alrz commented on Thu Dec 31 2015
@gafter Couldn't you read that more literally? 😄
@gafter commented on Thu Dec 31 2015
@alrz if/when we design this, we probably will go through all the implicit conversions and ask those questions.
@yufeih commented on Wed Jan 06 2016
What if the type is declared like:
This still won't compile today, but the compile have enough knowledge about the inferred type.
@gafter commented on Mon Jan 11 2016
We (the language design team) looked at this briefly last week. To summarize our understanding of the proposal, we begin with the two existing sections
and
The proposal is to modify the penultimate bullet of 7.5.2.11 to be more generous in when it succeeds.
The LDM notes that this is a technically incompatible change to overload resolution. As such it is unlikely that we could accept the change as proposed. Users tend to tar and feather us if we change the meaning of existing programs, and this change would do just that. A demonstration of that fact is left to the reader.
Having said that, all is not lost. Another approach would be to leave type inference alone, and modify 7.5.2.14 to define best common type in terms of the desired new rule, instead of deferring to 7.5.2.11. Alternatively, we could make the desired change to the language, and provide a tool for users to migrate (or check) their code from one language version to the next, warning if there is a change in the semantic meaning of their code between language versions. Neither option is as attractive as the original proposal, presuming it were not a breaking change.
@dsaf commented on Mon Jan 11 2016
Makes sense only when/if a critical mass of similarly invasive changes gets accumulated.
I am personally leaning towards @HaloFour 's opinion:
@realbart commented on Tue Oct 11 2016
Please don't implement this
What is the type of collections here?
In older .net-versions, the only common interface was IList.
However, in C#4.5 typed arrays also implement IReadOnlyCollection<>.
If you'd allow this kind of type inference, adding an interface in newer framework versions breaks existing code.
@dsaf commented on Tue Oct 11 2016
@realbart as mentioned above it could be an intersection type of common interfaces #4586.
@Opiumtm commented on Wed Oct 12 2016
I think interfaces should never be used in this "common-type" inference.
Only single common parent class should. So, if two classes share one common interface and no common parents, array type of
object
should be inferred - as object is a single common class.Reason: interfaces are somewhat a form of multiple inheritance. Multiple inheritance resolving in typing should always be explicit.
Use type priority order for some primitive types.
int -> long -> double
If any other primitive type encountered - use
object
common class instead.So, any unsigned integers, decimal values and single-precision float appearing in array with mixed primitive types should result in
object
common class and compiler should throw warning (not error).Any
null
in implicitly-typed array with only primitive types should result in NullableType argument of nullable should be inferred using same int -> long -> double logic
So
Structures of same type in array with any
null
should be inferred as T?[] - where T is a struct type. Any other value type alongside struct (primitive type, another struct) should result inobject[]
with compiler warning.Never take interfaces into consideration when inferring types. See above.
Interfaces are form of multiple inheritance and multiple inheritance should always be treated explicitly.
@Opiumtm commented on Wed Oct 12 2016
@dsaf @realbart
Interfaces are form of multiple inheritance so type inferring based on multiple inheritance is unreliable and definitely would break code. So any form of multiple inheritance (interfaces, for example) should always require explicit typing.
But use common parent class for type inference isn't such unreliable nor dangerous.
For your example
Type of
collections
variable should beobject[]
asobject
is a common base class for array and list.@jcouv commented on Mon Apr 17 2017
One part of this proposal (finding best common type between
1
andnull
to beint?
) has been discussed in LDM and is considered for a point release:https://github.com/dotnet/csharplang/blob/master/proposals/improved-common-type.md
Btw, I'll move this discussion over to csharplang repo. Feel free to continue discussion there.
Beta Was this translation helpful? Give feedback.
All reactions