dotnet / csharplang

The official repo for the design of the C# programming language
11.5k stars 1.03k forks source link

[Proposal]: List literals #3945

Closed TKharaishvili closed 4 years ago

TKharaishvili commented 4 years ago

Proposal Moved

Note: this proposal is being rolled into https://github.com/dotnet/csharplang/issues/5354.

We're going to lock this issue so that further discussion around it happens with the championed proposal.

List literals

Motivation

Despite it's Java-like origins C# has some features that make it feel lightweight. var keyword, tuples, lambdas and anonymous objects being some of them.

List initialization however falls behind:

var nums = new List<int> { 1, 2, 3 };

I've been doing some competitive coding recently and as you guys all know lists are all the rage over there and having to type that over and over again has not been fun. One might even consider creating a snippet which I am but maybe a more fundamental solution is worth the effort.

Detailed design

Enter list literals:

var nums = [ 1, 2, 3 ];

It shouldn't be too much of a headache to parse as far as I can tell. No other expression starts with a square bracket in C# if my memory serves me right.

Drawbacks

An empty list is a bit of a problem 'cause there's no way to tell the type. In that case I guess I'll have to live with the target typed approach:

List<int> nums = [];

I still see some value in that 'cause it's only painful for variable declarations. In case of argument passing, property default values and return statements the types are already there anyway.

Unresolved questions

There's a question of how powerful the type inference should be. The following:

var list = [ 1, 2, "three" ];

Should clearly be an error. (Unless union types show up one day, which I'm hoping they do)

But should the following have the type of List<int?>?

var nums = [ 1, 2, null, 3 ];

I think it's perfectly reasonable to not go further than that. For now at least.

CyrusNajmabadi commented 4 years ago

This is a dupe of https://github.com/dotnet/csharplang/issues/414 which covers dictionary and list literals (in all discussoins we have on the topic). Thanks though :)

TKharaishvili commented 4 years ago

@CyrusNajmabadi I did have a glance at that proposal but thought it only covered dictionaries. Having a quick look at it again I see mentions of dictionaries and arrays, not lists though :confused:

CyrusNajmabadi commented 4 years ago

It really covers all of it. We're aware ofthis space, though there is no proposal that has been found to suitably cover all the cases felt to be important. For example, special casing List/Dictionary for me is a non-starter. For one, we odn't even use those collections ourselves :) Any solution needs to allow literals but needs to work effectively the common collection types out there (including the immutable ones). It may be hte case that that comes through some additional extensions to make those existing types "literal-able", but it would need to eb part of any spec in order for me to consider it. Thanks! :)

TKharaishvili commented 4 years ago

@CyrusNajmabadi I understand the reasoning behind the wish to make the syntax generalizable, capable of covering immutable and maybe even concurrent collections.

I also understand that you guys use immutable collections in the Roslyn codebase and analyzers. I've spent some time tweaking the compilers myself. But there are some arguments for special casing List and maybe Dictionary:

  1. Beginners use those data structures frequently not their immutable counterparts. And making it easy on them makes the language more appealing. I've mentored some younger developers so I don't just make this up out of thin air.

  2. This is the reason why I mentioned competitive coding. In those algorithm like problems and tasks these are the collection types used more frequently as well. I've had job interviews where I had to solve a problem in 15 minutes. In a scenario like that every keystroke counts.

  3. I'd argue it's frequent enough in web development as well. I've been doing server-side .NET for quite a while and that also mostly involves regular collections rather than other ones.

  4. Prototyping, writing test code in the C# interactive window or the console. Trying out graphing API-s by giving them dummy data. Writing all the quick code would considerably benefit from this.

In conclusion, what I'm trying to say is that I understand and support the idea to make it general. But if that's not possible, I still see a lot of value in doing it for the regular collections only.

Thanks for taking the time to reply.

theunrepentantgeek commented 4 years ago

The language team have expressed a strong preference for ensuring that safer constructs are shorter (or, at least, no longer) to express than others.

For example, this is one of the reasons why let is being preferred over readonly var for assign-once local variables.

Having a shorter syntax for a literal list would be quite useful, but in light of this desire, special casing for List<T> and Dictionary<K,V> seems unlikely.

I guess one way to address this would be to require target typing (in the way you can now use new without specifying a type).

So this would be illegal, as no type is specified:

var nums = [ 1, 2, 3 ];

But both of these would be legal:

List<int> primes = [2, 3, 5, 7, 11];
ImmutableArray<int> fibs = [1, 1, 2, 3, 5, 8];

The real benefits would show up when passing values to methods:

void Transmogrify(List<string> words) { ... }

Transmogrify(["this", "that", "other"]);

However, I can already see ways that this starts to founder badly - just consider the impact of generics, interfaces, etc.

CyrusNajmabadi commented 4 years ago

@TKharaishvili thanks for your htoughts on this :)

svick commented 4 years ago

@theunrepentantgeek At that point, I don't see much advantage of the proposed syntax over the existing (in C# 9.0) target-typed new, e.g.:

List<int> primes = new() { 2, 3, 5, 7, 11 };
Transmogrify(new() { "this", "that", "other" });

The disadvantages of this approach are that it's slightly longer and that it doesn't support immutable types.

alrz commented 4 years ago

it doesn't support immutable types.

Isn't that the other way around? ;)

CyrusNajmabadi commented 2 years ago

Note: this proposal is being rolled into https://github.com/dotnet/csharplang/issues/5354.

We're going to lock this issue so that further discussion around it happens with the championed proposal.