dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.11k stars 4.04k forks source link

C# 7 Work List of Features #2136

Closed MadsTorgersen closed 7 years ago

MadsTorgersen commented 9 years ago

(revision circa April 26 2016, clarifying edit June 14, 2016)

This is a list of features are looking at for C# 7, roughly categorized according to our current level of interest and estimated plausibility.

Please don't infer anything about the final shape of C# 7 (or future versions). The list is a tracking mechanism for work, not a description of the outcome. We have a long way to go yet!

Each bucket is in no particular order. I'll try to think of a more systematic way of cross-referencing with proposals and notes, but wanted to get the list out there.

I'll keep the list updated as we look at more feature ideas and change our minds about the relative importance.

Strong interest


See also Language Feature Status (compiler team)

Aaronontheweb commented 9 years ago

Immutable types dotnet/csharplang#2543 would also be amazing.

JayBazuzi commented 9 years ago

I often wish for extension methods in nested private static classes, although "Allow extension methods in non-static classes" would cover most of that need.

mariusschulz commented 9 years ago

If I had to pick a single feature that excites me most, it would without doubt be Algebraic data types. Very happy to see it on the Strong interest list!

dotnetchris commented 9 years ago

@JayBazuzi we only wanted them in nested private classes because of the arbitrary requirement that they couldn't be in a nonstatic class

RobertGBryan commented 9 years ago

What about a common sense and reasonably easy to implement feature to retrieve a key from a Dictionary, HashSet, SortedDictionary, or any other container class that uses keys?

Right now, only values can be retrieved from a Dictionary - not the key. Unless iterating through the dictionary with a foreach loop - which would be prohibitively expensive when doing a simple look up. It would be nice if a method could be provided that would return the key/value pair for a given key from a matching "key". The reason why it would be useful is because the Equals method does not necessarily mean that 2 objects are exactly equal - since the Equals method can and often does only use a subset of the fields of a class to make that determination. I have come across cases where it would have been quite helpful to access the stored key in the dictionary when my code found the item in the dictionary. There were other fields in the stored key that I needed to access that were not present in the key used to access the dictionary, so I had to use the suggested work around given in the link above.

wesnerm commented 9 years ago

@RobertGBryan, it's a simple thing to include the key with the value or to make the value a tuple. If there's a canonical name, it should be probably included with the value.

RobertGBryan commented 9 years ago

@wesnerm, Sounds like you are suggesting using the work around specified in the link above. The drawback as pointed out by the original poster in that link is that it adds complexity as well as needlessly takes up more memory. How hard would it be to provide a method to return the key and value? Wouldn't this be a fairly simple task to implement?

wesnerm commented 9 years ago

@HaloFour,

"Adding a new "default method" would still leave a blank spot in the vtable slot that older runtimes would not know to wire up to that static instance method. You could have newly compiled classes do that automagickally but not already compiled assemblies."

No, there would be no blank slot. It's not a runtime feature, but a compiler feature.

In the IL, there would always be some method assigned to slot. In C# 7.0, the compiler would implement a private instance method that calls the static interface method. (Calls to static interface methods are actually supported by older versions of C#.)

.method private virtual void ClassInterfaceMethod()
{
    .override IInterface::InterfaceMethod
    ldarg.0
    call void IInterface::InterfaceStaticMethod(Interface)
    ret
}

InterfaceStaticMethod and InterfaceMethod might have the same name, since that is possible in IL.

An older compiler using a library with a default interface method would not know about it and would require the developer to always implement either a explicit or implicit interface implementation. A developer using the older compiler could recreate the same implementation as C# 7.0 manually.

void IInterface.ClassInterfaceMethod()
{
    IInterface.InterfaceStaticMethod(this);
}

Default implementations can be implemented with attributes on the static interface method, just like with extension methods or param arrays. C# 7.0 would recognize the default implementations automatically when a user-provided implementation is missing. With no performance loss, C# 7.0 would locate a static method of the same name taking the same arguments (including the this parameter) and checking for the presence of a DefaultInterfaceMethodAttribute on the static method.

HaloFour commented 9 years ago

@RobertGBryan You should suggest that to the CoreFX Team. They consider possible API changes to the framework.

thomaslevesque commented 9 years ago

@RobertGBryan, that's a library issue, not a language issue. That won't be fixed by a new feature in the language.

HaloFour commented 9 years ago

@wesnerm That would break all existing implementers of that interface that are compiled outside of that project. That defeats most of the purpose of "default methods" which is the ability to add new trivial methods to an existing interface without requiring recompilation of implementing classes.

drothmaler commented 9 years ago

If you are going to implement Null safety in the Kotlin way, maybe you could check out a few of their other concepts too. I think especially the concepts of smart casts and delegated properties could be really useful...

String templates, first-class delegation, extension properties and singleton objects are also nice.

BTW: I think delegated properties (maybe in combination with first-class delegation?) could also solve the INPC problem.

Tomamais commented 9 years ago

Why not Metaprogramming? :'(

lukebuehler commented 9 years ago

+1 Type providers! Please!

SimonCropp commented 9 years ago

@MadsTorgersen can u elaborate on "compile time attributes"?

SimonCropp commented 9 years ago

Enum and generic constraints please so i can delete this project https://github.com/Fody/ExtraConstraints

chassq commented 9 years ago

Not sure how this fits in but would like to see Enums made more useful. Something like java Enums. I cannot say how many times I would like to have a bit more information attached to the Enum (e.g. a description). Can be done with [Description] attribute today but just would be nice if Enums were more extensible. The other thing would be the capability to do more generic work with Enums. Hope this makes some sense.

khellang commented 9 years ago

What happened to duck-/structural typing? I seem to recall it was mentioned in one of the design note issues... That would be really awesome. Or even a hack like Assembly Neutral Interfaces :smile:

eamodio commented 9 years ago

+1 for structural typing. That would be awesome. Spoilt by TypeScript.

adamralph commented 9 years ago

Excuse my ignorance, but what is INPC?

mcintyre321 commented 9 years ago

INotifyPropertyChanged - I guess it's talking about an automatic implementation a la ES6 Object.Observe

I personally would love this (especially recursive INPC) for doing object diffing of viewmodels and change tracking for reactive server side views and stuff.

adamralph commented 9 years ago

@mcintyre321 thanks. Never used it :stuck_out_tongue:

TwoRedCells commented 9 years ago

I don't think #154 would require CLR support, but if it does I'd be interested how. When I designed it, I envisioned it as a compile-time language-only feature.

I can see how dotnet/roslyn#129 would require run-time support.

TwoRedCells commented 9 years ago

@khellang I think #154 could be considered Duck typing.

TwoRedCells commented 9 years ago

@RobertGBryan in case you weren't aware, IDictionary, IDictionary<TKey,TValue>, HashTable, Dictionary<TKey,TValue> etc. all implement IEnumerable. Specifically, Dictionary<TKey,TValue> implements IEnumerable<KeyValuePair<TKey,TValue>> which I think is what you're looking for. It also has Keys and Values properties that you can use to iterate them separately, if desired.

MpDzik commented 9 years ago

+1 for Nullability tracking (Proposal: dotnet/roslyn#227)

orthoxerox commented 9 years ago

+1 for ref locals. When you have a very hot number-crunching loop, you have to resort to an array of structs to hold your data to improve data locality, and to shave off the final milliseconds you need to avoid copying the element you are processing into a local. This either means recalculating the offset again and again or extracting the loop body into a static method with a ref parameter. The latter option is the fastest, but can be confusing to those supporting the code.

whoisj commented 9 years ago

Can I please add a new feature request, if this isn't the place to do so please tell me where the right place is.

Not sure what to call it, but basically I want the ability to pass a reference into a method and know that method will not take an additional reference. For example, if I allocate a large block of memory and I pass a reference to that allocation into a method, I would like to know that the method will not keep a reference to the memory thus preventing the GC from doing its job.

Effectively I'd like parameter operator which creates a contract with the call that the method will not take a reference to the parameter nor will it is pass the reference to another method which doesn't support the same contract.

A use-case could be something as simple as Encoder's .GetString method.

public string GetString(&byte[] bytes)

Where the & is used to signify that the reference cannot be held on to.

HaloFour commented 9 years ago

@whoisj

Can I please add a new feature request, if this isn't the place to do so please tell me where the right place is.

You can create a new issue for the proposal. Then it will be tracked separately and can have its own dialog.

whoisj commented 9 years ago

@HaloFour yay, thanks!

natalie-o-perret commented 9 years ago

Any news about the constraints support for delegates and enums? Here is a link to bring some memories back: http://blogs.msmvps.com/jonskeet/2009/09/10/generic-constraints-for-enums-and-delegates/

dsaf commented 9 years ago

@ehouarn-perret Additional constraints are explicitly mentioned in the opening post itself: "Small but useful" and "Interesting but require CLR support" sections.

HaloFour commented 9 years ago

To note, as mentioned on Jon Skeet's blog and on here and CodePlex numerous times, supporting delegates or enums as generic type constraints are both currently supported by the CLR, just not by C#. C# already recognizes and enforces said constraints if you reference another assembly that uses them.

Here are the two existing proposals for this:

dotnet/roslyn#158 Proposal: Support System.Delegate as a generic constraint dotnet/roslyn#262 Proposal: support an enum constraint on generic type parameters

natalie-o-perret commented 9 years ago

@HaloFour @dsaf Alright then, glad to know that those suggestions are still around and have been considered for C# 7 :-)

I'm already aware of what Jon Skeet has found (a long time ago, about 6-7 years ago). And fully agreed as it has been already pointed out many times this is already supported by the CLR. Sadly, C# still lacks its language counterpart.

Thanks about the links, that was exactly what I was looking for.

badja commented 9 years ago

Shouldn't dotnet/roslyn#1384 (Family AND Assembly access modifier) be on this list, given that it was going to be included in C# 6 but didn't quite make it? As a minor enhancement that doesn't require CLR changes, it probably belongs in the Small but useful bucket.

MgSam commented 9 years ago

@badja It's not bucketed because Mads is probably still having nightmares after the wars on CodePlex over what word to call the operator.

thomaslevesque commented 9 years ago

@MgSam commented on Jul 1, 2015, 3:17 PM GMT+2:

@badja It's not bucketed because Mads is probably still having nightmares after the wars on CodePlex over what word to call the operator.

IMO it's better to have this feature even if the chosen keyword isn't perfect, than not have it just because the team and the community couldn't agree on a keyword.

whoisj commented 9 years ago

IMO it's better to have this feature even if the chosen keyword isn't perfect, than not have it just because the team and the community couldn't agree on a keyword.

Just learn from C++/Cli folks and move on.

thomaslevesque commented 9 years ago

Just learn from C++/Cli folks and move on.

That was the initial plan... C++/CLI uses protected private. C# 6 was initially supposed to use private protected, but everyone hated it. That's what caused the fruitless debate to pick a different keyword.

HaloFour commented 9 years ago

@thomaslevesque

Can't please everyone. On the Internet it's more like "can't please anyone." I think they should just go with the same keywords as C++/CLI* and implement it. It's a minor win and being consistent should reduce potential confusion, although the use-cases are so limited it probably won't come up much anyway.

* Yes, I am aware that private protected and protected private are the same thing given that the modifier keywords are permitted to be in any order.

knat commented 9 years ago

protectedandinternal and protectedorinternal is a nearly perfect choice. I can't understand why English speakers so care about the 'purity'. Yes, protectedandinternal and protectedorinternal are very ugly, but they are very very CLEAR. There will be 7 access modifiers:

HaloFour commented 9 years ago

@knat Doesn't fit with how access modifiers are already specified in C#.

If C# doesn't just copy C++/CLI and implement with the original plan it's best to just leave the feature out because the "keyword wars" that ensued are the epitome of a waste of time.

dsaf commented 9 years ago

@HaloFour I think the Roslyn team is capable of and should really make firm decisions like this. Whatever it's called as long as it's done.

MadsTorgersen commented 9 years ago

I edited the list to reflect decisions from dotnet/roslyn#3912 and dotnet/roslyn#3910.

alrz commented 9 years ago

method references as implemented in java are very neat and prevent a lot of unnecessary lambda expressions.

thomaslevesque commented 9 years ago

method references as implemented in java are very neat and prevent a lot of unnecessary lambda expressions.

You mean doing something like that items.Where(IsValid) instead of items.Where(i => IsValid(i))? It's already possible in C# (actually it was possible before lambda expressions even existed in C#).

A nice thing that Java 8 does and C# doesn't, though, is allow constructors to be used as method references, e.g. items.Select(SomeClass::new). I'd like to see that in C#, but I suspect it would require some changes at the CLR level too, because currently you can't create a delegate directly from a constructor.

alrz commented 9 years ago

@thomaslevesque yes it's already possible but not from the outside of the class. something like this customers.Select(Customer::Name) . However, you can create delegates from instance members via Delegate.CreateDelegate .

thomaslevesque commented 9 years ago

@thomaslevesque yes it's already possible but not from the outside of the class

The fact that the method is in another class is irrelevant, as long as it's public. My example above would work just as well if IsValid is in another class:

something like this customers.Select(Customer::Name)

Well, in this case it's a bit different, because Name is a property, not a method (I assume). I think the point you're trying to make is that we can't reference an instance method this way if we don't have an instance? It's not something that I miss personally, but I see how it could be useful.

alrz commented 9 years ago

it's a bit different, because Name is a property, not a method (I assume).

I'm relying on the fact that properties are internally implemented as methods, e.g. get_Name in this case.

thomaslevesque commented 9 years ago

I'm relying on the fact that properties are internally implemented as methods, e.g. get_Name in this case.

Yes, but there are two methods (for read-write properties): get_Name and set_Name. Which one would Customer::Name refer to? I'm not against such a feature, but it would have to be carefully thought through.