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

Proposal: Dictionary Literals #414

Closed
migueldeicaza opened this issue Apr 6, 2017 · 41 comments
Closed

Proposal: Dictionary Literals #414

migueldeicaza opened this issue Apr 6, 2017 · 41 comments

Comments

@migueldeicaza
Copy link

migueldeicaza commented Apr 6, 2017

Proposal Moved

Note: this proposal is being rolled into #5354. So while dictionary-literals on their own is "likely never", the space of 'collection literals' (which includes dictionaries) is championed and is proceeding with its design.

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

Dictionary Literals

Summary

Dictionaries are a very common data structure, this is one step to make dictionaries better supported at the language level than they currently are.

Introduce a simpler syntax to create initialized Dictionary<TKey,TValue> objects without having to specify either the Dictionary type name or the type parameters. The type parameters for the dictionary are inferred using the existing rules used for array type inference.

    /// The following are equivalent
    var x = new Dictionary <string,int> () { { "foo", 4 }, { "bar", 5 }};

    var x = ["foo":4, "bar": 5];

This makes working with dictionaries simpler in C# code. I will provide a separate proposal for a shorthand for the Dictionary type and Lists types.

Similar syntax exists in other languages in the space like F# and Swift.

Details

This is bound to the Dictionary<TKey,TValue> from mscorlib.dll. Future work can explore whether it is viable to use this as a instance initializer for other types.

The grammar is extended as follows:

expression 
    : ...
    | dictionary-literal-expression
    
dictionary-literal-expression:
    | "[" key_pair_list_opt "]"
    ;
    
key_pair_list_opt
    : /* empty */
    | key_pair_list
    
key_pair_list
    : keypair
    | keypair_list "," keypair
    
keypair
    : expression ":" expression  

The argument types for the Dictionary are computed similarly to how they are computed for array initializers, the type inference is applied over all the keys to determine the key type. Then type inference is applied over all the values to determine the value type.

A working proof of concept implemented on top of Mono’s C# compiler can be seen here:

https://github.com/mono/mono/compare/master...migueldeicaza:dictionary-literals?expand=1

@john-cd
Copy link

john-cd commented Apr 6, 2017

Are you aware of the C# 6.0 syntax? http://www.kunal-chowdhury.com/2015/01/csharp-6-dictionary-initializer.html#IsRqzKMwhPJejbC1.97 ?

Otherwise consider using the Python or JSON syntax. JSON literals would be welcome.

@Mafii
Copy link

Mafii commented Apr 6, 2017

Would these be compile time constants?

@jveselka
Copy link

jveselka commented Apr 6, 2017

Even array doesn't get it's "literal" type and it is more closely tied to the language. If we get this, we should get it for arrays as well. However I would go the opposite way, aligning array initializer expressions and dictionary initializer expressions.
Currently allowed for array:

var arr = new int[] { 1, 2 }; //optionally with length
var arr = new[] { 1, 2 }; //interestingly, can not specify length
int[] arr = { 1, 2 }; //must specify target type
                      //interestingly 'int[] arr; arr = { 1, 2 };' does not work

Currently allowed for dictionaries:

var dic = new Dictionary<int, string> { { 1, "one" }, { 2, "two" } }; //optionally with capacity
var dic = new Dictionary<int, string> { [1] = "one", [2] = "two" }; //optionally with capacity

If we want it improved, it should be done in the same spirit, which brings me to this:

var dic = new { { 1, "one" }, { 2, "two" } }; //infers Dictionary<int, string>
var dic = new { [1] = "one", [2] = "two" }; //infers Dictionary<int, string>
//possibly 'new<,>' instead?

var dic = new<object,string> { { 1, "one" }, { 2, "two" } }; //uses Dictionary<object, string>
var dic = new<object,string> { [1] = "one", [2] = "two" }; //uses Dictionary<object, string>
//may not be needed as this would do the same:
//  var dic = new { { (object)1, "one" }, { 2, "two" } }; //infers Dictionary<object, string>

it however bakes in System.Collections.Generic.Dictionary<TKey,TValue> into language which may be a bad idea.

@migueldeicaza
Copy link
Author

migueldeicaza commented Apr 6, 2017

@john-cd yes, I am aware of the C# 6.0 syntax. It does not remove the need for specifying the type or the type parameters.

@Mafii They would not be constants in a traditional sense, as the result is a Dictionary<TKey,TValue> which can be mutated.

@louthy
Copy link

louthy commented Apr 6, 2017

@migueldeicaza I think the problem with this is that it raises Dictionary<A, B> to special status. Which is problematic for those of us that want to enforce immutability in our world. It's directing the inertia in the wrong direction.

Even making System.Collections.ImmutableDictionary the default would be problematic for those of us who develop replacement collections libraries that DontAgreeWithTheEpicJavaStyleNaming of ImmutableDictionary.

In language-ext I'm able to get some very concise construction of its Map type thus:

    var x = Map(("foo", 4), ("bar", 5));   

   // x is a Map<string, int>

Map is a static function that is accessed via using static LanguageExt.Prelude takes a params (A, B)[], and returns a Map<A, B>.

So it seems to me this would unnecessarily punish other implementations, and discourage safer coding with immutable types (they shouldn't be the default either, but this would make other types into second class citizens IMHO).

@MgSam
Copy link

MgSam commented Apr 6, 2017

Is specifying the type of the dictionary explicitly really such a big burden? It doesn't matter how long the set of things going into the dictionary is, you only need to specify the type once.

How often are people initializing dictionaries to a set of hard coded values?

Seems like a lot of new syntax for comparatively little benefit.

@AlgorithmsAreCool
Copy link

I just had to write some code in F# for the first time in a while and I had forgotten how wonderful not specifying types can be.

But when i am in C# land, my mentality is different. It is somewhat rare for me to specify collection literals, i'm typically initializing empty and then filling them from some data source. As a result i don't think this syntax (albeit pretty) pays for itself especially since we already have 2 different way to initialize dictionaries.

@thargy
Copy link

thargy commented Apr 7, 2017

Pretty much agree with all the down-vote comments on here. The inconsistency with Array initialisation, the promotion of Dictionary<,> over other similar types (Immutable, Concurrent), the further dilution of type clarity, etc.. We already had the C# 6.0 addition (which I really didn't think was needed either and felt it added nothing). Bringing more in line with Arrays would at least be a logical step, even though I still think we have too many styles already.

I'm all for change and you can count me as a fan of many of the latest editions, but I think the bar needs to be a little higher than this proposal meets.

@Mafii
Copy link

Mafii commented Apr 7, 2017

I am in favour of custom literals like vb.net instead of this one - it would not favour any dictionary type over any other.

Or there could be a IHasDictionaryLiteral interface that would allow to interpret the dictionary at design time for any type, but that would be confusing/complex and probably not worth it.

@louthy
Copy link

louthy commented Apr 8, 2017

Here's some food for thought. In my Map implementation that I mentioned above, it's possible to use tuples to initialise a Map.

    var x = Map(("foo", 4), ("bar", 5));  

I wondered if it'd be possible to just use a single-item tuple of tuples and the use an implicit operator to convert to the type required.

    Map<string, int> x = (("foo", 4), ("bar", 5));

And it is possible. This doesn't solve the issue of having to specify the type, but for method arguments, fields, or properties where the type is already known you wouldn't have to specify it at the site.

It does mean having to create operator overloads for however many items you'd be willing to support (see below). And it's certainly not the most efficient method of construction; but I wonder if there's some avenue here that could be explored? It's more of a thought experiment than anything; it certainly has a more attractive syntax.

public static implicit operator Map<K, V>(ValueTuple<(K, V)> items) =>
    new Map<K, V>(new [] { items.Item1 });

public static implicit operator Map<K, V>(((K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4, items.Item5 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4, items.Item5, items.Item6 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4, items.Item5, items.Item6, items.Item7 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4, items.Item5, items.Item6, items.Item7, items.Item8 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4, items.Item5, items.Item6, items.Item7, items.Item8, items.Item9 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4, items.Item5, items.Item6, items.Item7, items.Item8, items.Item9, items.Item10 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4, items.Item5, items.Item6, items.Item7, items.Item8, items.Item9, items.Item10, items.Item11 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4, items.Item5, items.Item6, items.Item7, items.Item8, items.Item9, items.Item10, items.Item11, items.Item12 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4, items.Item5, items.Item6, items.Item7, items.Item8, items.Item9, items.Item10, items.Item11, items.Item12, items.Item13 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4, items.Item5, items.Item6, items.Item7, items.Item8, items.Item9, items.Item10, items.Item11, items.Item12, items.Item13, items.Item14 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4, items.Item5, items.Item6, items.Item7, items.Item8, items.Item9, items.Item10, items.Item11, items.Item12, items.Item13, items.Item14, items.Item15 });

public static implicit operator Map<K, V>(((K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V), (K, V)) items) =>
    new Map<K, V>(new[] { items.Item1, items.Item2, items.Item3, items.Item4, items.Item5, items.Item6, items.Item7, items.Item8, items.Item9, items.Item10, items.Item11, items.Item12, items.Item13, items.Item14, items.Item15, items.Item16 });

@migueldeicaza
Copy link
Author

Updated branch allows implicit conversions to Dictionary-shaped objects, just like collection initializers, so this works:

Hashtable x = ["foo":"bar"];

It requires the type to be known, otherwise if the type is inferred, we default to the original Dictionary<T,K>.

Patch:

https://github.com/mono/mono/compare/master...migueldeicaza:dictionary-literals-implicit-conversion?expand=1

@JoergWMittag
Copy link

I used to think that having lots of different literals was important. I'm not so sure anymore.

My "main" language is Ruby, which has a rich set of literals:

  • Strings (there's actually no less than 11 different string literals (including special syntax for single-character strings: ?a), and that's just the ones that I can think of off the top of my head).
  • Symbols
  • Arrays
  • Arrays of Strings (Yes, there's special syntax for those)
  • Arrays of Symbols (likewise)
  • Hash (Ruby's name for Map/Dictionary)
  • special Syntax for Symbol keys within a Hash, mirroring ECMAScript Object Literal syntax to some degree
  • Regexps
  • Floats
  • Integers
  • Rationals
  • Complex Numbers
  • Ranges
  • Lambdas
  • true, false, nil

However, after using Scala for a while, I realized that Scala has no collection literals, and in fact only a rather small number of literals, and I didn't miss them. The reason for this is Scala's otherwise concise syntax, which makes special literals mostly unnecessary, because factory methods are syntactically convenient to use anyway:

  • Array(1, 2, 3) // equivalent to Array.apply(1, 2, 3)
  • Seq(1, 2, 3)
  • Map(1 -> "One", 2 -> "Two") // Map.apply simply takes a sequence of Tuple2[K, V], and there is an "Extension Method" called -> on Any that returns a 2-Tuple

Scala's string interpolation syntax allows "fake" user-defined literals, for example, the Scala stdlib provides an interpolator for regexs: r"a*.b(c+)". One could also create an interpolator for XML: xml"<foo><bar></bar></foo>".

Really, the only "complex" literals Scala has, are Tuples and Lambdas. (It also has XML Literals, but those have been deprecated for a long time and are considered a mistake.)

Personally, I would prefer the following over selectively adding individual new literals for specific types:

  1. Allow overloading of existing literals, for example by changing them into method calls. E.g. Ioke and Seph do this, for example 1234 is actually interpreted as a call to internal:createNumber("1234"). There is some precedence for this in C♯: lambda literals are overloaded on their result type.
  2. Make factory methods syntactically lightweight.
  3. Powerful string interpolation like Scala (in particular, in Scala, the result type of an interpolated string can be anything, it doesn't have to be String).
  4. User-defined literals.

In general, I am a fan of powerful general language features that make it possible to implement stuff in libraries as opposed to changing the language spec. Sure, you can add dictionary literals to the language. And then someone wants regex literals. Or complex literals. Or set literals. Or rational literals. Or money literals. I would much rather have a feature that allows users to implement all of those as libraries than having to change the language every time someone comes up with an idea for a new literal type.

@john-cd
Copy link

john-cd commented May 6, 2017

I second Joerg on the use of Scala-like features

@mattwar
Copy link

mattwar commented May 12, 2017

@louthy could you just use a params array of tuples

   Map<K,V>(params (K key, V value)[] keyValuePairs)

@louthy
Copy link

louthy commented May 20, 2017

@mattwar Hi Matt, I already do that for construction. My examples were related to the implicit conversion operator. Which as far as I'm aware can't take a sequence of tuples.

@gulshan
Copy link

gulshan commented Jul 24, 2017

I support this proposal and I think lists and dictionaries/maps are the two most fundamental types of collections used everywhere and should be syntactically lifted to language level. I believe this will make the beginners' life lot more easier. I also want to see this proposal for Lists as promised by the author. Another thing I would suggest is lifting the types also using same notation- [int] becoming List<int> and [string : int] becoming Dictionary<string, int>. I think this is also consistent with the C# philosophy, as tuples(literals and types) were lifted to language level.

@jnm2
Copy link
Contributor

jnm2 commented Jul 24, 2017

I think this is also consistent with the C# philosophy, as tuples(literals and types) were lifted to language level.

That's not my understanding. No existing BCL type was lifted to become a syntactic construct; rather, ValueTuple was created only after the syntactic construct was desired for separate reasons.

@gulshan
Copy link

gulshan commented Jul 24, 2017

Tuples did had System.Tuple as predecessor. And F# lifted it to language level long before C#. While doing that in C#, features like naming members were added. Then decision was made to use struct instead of class for performance reason. That's how ValueTuple was born instead of enhancing System.Tuple class. This is my understanding though. :)

@HaloFour
Copy link
Contributor

"Tuples" in the C# language weren't an attempt to "promote" the existing System.Tuple type to a language construct. The goal was to facilitate the syntax and behavior of returning multiple values from a function and to treat those values as individual locals/parameters and not as any specific container type.

This is quite different from lists/dictionaries where there can be many different implementations and the language has gone to some length to avoid endorsing even the BCL flavors of those implementations.

@iam3yal
Copy link
Contributor

iam3yal commented Jul 25, 2017

I want to have more aggressive type inference for C#, especially when it comes to generics but as much as it sounds attractive I wouldn't like to have a special syntax for a dictionary just because... I can't see the value in it but if it's going to be expanded to other types then it can be more interesting and appealing to me but even then I think that the proposed syntax needs some work.

@gulshan
Copy link

gulshan commented Jul 26, 2017

Instead of my previous proposal of [T] meaning List<T> and [Tkey : TValue] meaning Dictionary<TKey, TValue> here, now I think the lifting should be bound to interfaces rather than concrete types. That means, [T] is IList<T> and [TKey : TValue] means IDictionary<TKey, TValue>. Then the underlying implementation can be any concrete type chosen by the Roslyn team, which will be normally hidden from the user.

I think this idea of array/list and dictionary literals is heavily influenced by Swift. We can take a look in their documentation (search with 'literal').

@jnm2
Copy link
Contributor

jnm2 commented Jul 26, 2017

Without a bloat of default interface methods, those interfaces are severely underpowered to be used as the all-purpose dictionary and list.

@migueldeicaza
Copy link
Author

migueldeicaza commented Aug 15, 2017

I also love the idea of [foo] being a List<foo> and [foo:bar] being a Dictionary<foo,bar>, but I think that it is independent of this discussion. It belongs in its own proposal - as an aside, I looked into adding this to the compiler, but the grammar conflicts in many ways, so we would need an alternative syntax for it.

@MadsTorgersen MadsTorgersen added this to the 8.0 candidate milestone Oct 9, 2017
@Richiban
Copy link

I think that perhaps the most C#-ish way forward is to do something similar to what arrays do now with a special initialisation syntax:

public class A
{
	private readonly string[] values = new int[]
	{
		"one", 
		"two", 
		"three"
	}
}

Can currently be written as:

public class A
{
	private readonly string[] values = 
	{
		"one", 
		"two", 
		"three"
	}
}

Can we allow the following:

public class B
{
	private readonly Dictionary<string, int> values = new Dictionary<string, int>
	{
		{ "one",   1 },
		{ "two",   2 },
		{ "three", 3 },
	}
}

To instead be written as:

public class B
{
	private readonly Dictionary<string, int> values = 
	{
		{ "one",   1 },
		{ "two",   2 },
		{ "three", 3 },
	}
}

@Joe4evr
Copy link
Contributor

Joe4evr commented Oct 18, 2017

Can we allow the following:
[...]
To instead be written as:

Well, once target-typed new() (#100) lands, it can be:

private readonly Dictionary<string, int> values = new()
{
    { "one",   1 },
    { "two",   2 },
    { "three", 3 },
}

@gulshan
Copy link

gulshan commented Jun 5, 2018

Just came into mind- [T] as List<T> would conflict with the attribute [FooAttribute] syntax. My bad.

@jnm2
Copy link
Contributor

jnm2 commented Jun 5, 2018

@gulshan Can you give an example of where it would conflict? The locations where you can specify a list expression or an attribute seem mutually exclusive.

@gulshan
Copy link

gulshan commented Jun 5, 2018

Actually it would be best to term it as "confusing". Now, [Something] instantly reminds of attributes to C# devs. When it will have another meaning depending on the context, that may confuse people. For example- void MyFunc([Attr][int] intList). There can even be conflicts we don't know yet.

@jnm2
Copy link
Contributor

jnm2 commented Jun 5, 2018

@gulshan foo[Something] doesn't instantly remind me of attributes.

@AustinBryan
Copy link

I like it. It's like a third the length of what we currently have to do.

@dsaf
Copy link

dsaf commented Aug 21, 2018

I don't like the syntax. Currently square brackets are used for index and size, curly brackets are used for elements. This problem should be solved through new general language features like global aliases and better inference:

using global Map = Systems.Collections.Generic.Dictionary;
...
Map x = new {{"foo",4}, {"bar",5}};//Length comparable to:
//var x = ["foo":4, "bar": 5];

If anything:

var x = {{"foo",4}, {"bar",5}};

@apkd
Copy link

apkd commented Oct 1, 2018

I'm guessing this particular ship has sailed because we already have so many ways to initialize objects and collections. Still, can't help but feel slightly envious of the low-effort inline object definitions that JavaScript/TypeScript has. In the world of C# it could look something like this:

var obj = new { // or maybe even omit "new", although the cost is low if we only use it to open
    field = "value",
    anotherField = 16f,
    objectReference = objectGetter.GetObject(),
    tuple = (3, 5, 7, "surprise"),
    array = [1, 2, 3, 4, 5],
    objectArray = [
        { x = 3, y = 8}, // allow omitting of "new" inside an anonymous object declaration
        { x = 7, y = 5},
        { x = 0, y = 1},
    ],
    dictionary = [
        ["key1": "value1"], // dictionary syntax proposed above
        ["key2": "value2"],
    ],
    altDictionarySyntax = {   // more like the old dictionary initialization
        { "key1", "value1" }, // syntax, but can we distinguish it from the
        { "key2", "value2" }, // anonymous object syntax if we omit "new"?
    },                        // or maybe use ":" as a key-value separator instead?
};

var json = JsonConvert.SerializeObject(obj); // feels good, man

Some of the above is actually valid C# already. This is much more in line with the way you can effortlessly define tuples with the new C#7 syntax. In my opinion, fits together nicely overall.

@alrz
Copy link
Contributor

alrz commented Dec 12, 2018

Aside from a few suggested alternatives that we have today, the problem with the proposal is that it only optimize for Dictionary and possibly List types when the target type is not known. As soon as you depend on another collection type, you'd need a target type.

I wonder if more generalized features like new() and potentially other type inference improvements, could help with use cases discussed here. In other words, my question is how "dictionary literal" is compared to a stronger type inference in general,

@gafter gafter added this to 8.0 Candidate (not started) in Language Version Planning Mar 6, 2019
@MadsTorgersen MadsTorgersen moved this from 8.0 Candidate (not started) to 9.0 Candidate in Language Version Planning Apr 29, 2019
@gafter gafter modified the milestones: 8.0 candidate, 9.0 candidate Apr 29, 2019
@gafter
Copy link
Member

gafter commented Aug 28, 2019

LDM looked at this today. We think there are a number of interesting use cases around initializing data, particularly for things like immutable dictionaries. We don't find the existing syntax for initializing a dictionary that onerous, nor do we see it as a frequent pattern in code that would benefit much from a language feature. We thing that the general area of initializing data should be looked at again after we do records and withers. But this proposal doesn't feel compelling.

@gafter gafter modified the milestones: 9.0 candidate, Likely Never Aug 28, 2019
@gafter gafter moved this from 9.0 Candidate to REJECTED in Language Version Planning Aug 28, 2019
@333fred 333fred removed this from REJECTED in Language Version Planning Feb 6, 2021
@aloisdg
Copy link
Contributor

aloisdg commented May 19, 2021

@333fred you removed this proposal from REJECTED. I think it means that the proposal was deleted from this list. Is there any chance in the short term to see it again?

@333fred
Copy link
Member

333fred commented May 19, 2021

@333fred you removed this proposal from REJECTED. I think it means that the proposal was deleted from this list. Is there any chance in the short term to see it again?

No. I removed every proposal from the planning board because we didn't use it and didn't update it, so it showed often-incorrect data for current proposals. Unfortunately, removing everything then showed up in all the issues, leading to just as much confusion. The milestone of the issue is still Likely Never, LDM has not discussed this since.

@CyrusNajmabadi
Copy link
Member

Note: this proposal is being rolled into #5354. So while dictionary-literals on their own is "likely never", the space of 'collection literals' (which includes dictionaries) is championed and is proceeding with its design.

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

@dotnet dotnet locked as resolved and limited conversation to collaborators Oct 6, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests