-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Please extend the object-initialization syntax so that json literals could literally initialize json data #6949
Comments
See also #6673, which we are not likely to do because it maps an identifier to a string rather than evaluating it as an expression. |
@AnthonyDGreen This is mostly a placeholder. You're welcome to fill it in with more detail. |
@gafter You mention "object initializers" specifically, would this apply to any object or is this more specific to dictionaries? public class Person {
public string Name { get; set; }
public int Age { get; set; }
}
Person person = new Person() {
"Name" : "Bill Gates",
"Age" : "60"
}; |
@HaloFour The intent is that this would use a pattern of construction methods common to types such as |
@gafter Interesting, so a type would still need to be specified, or could there be a default type for the literal? var dict = new Dictionary<string, string>() { "Name" : "Bill Gates", "Age" : "60" };
var json = new JObject() { "Name" : "Bill Gates", "Age" : "60" };
var other = { "Name" : "Bill Gates", "Age" : "60" }; // legal? what am I? |
@HaloFour Good question. In @AnthonyDGreen 's prototype, it would look for any type named |
@gafter Very interesting. I'm curious if/how that might evolve into something a little more general purpose, unless the language team is comfortable making a loose dependency between C# and JSON.NET. |
@gafter So these are literally json literals? I thought this would be a concise syntax for dictionaries and lists (by default) which can be used with other types like using JObject = System.Collections.Generic.Dictionary<string,object>; // object? and it doesn't even support type inference. |
@alrz I'm gathering that the demonstrated prototype happened to behave in that way and that this proposal seeks to iterate on the underlying idea. |
I think making lists and dictionaries a language feature (like tuples) with a special type and initialization syntax (which is not limited to // infers a (int: int)
var map = { 1 : 2 };
// equivalent to
Dictionary<int, int> map = new Dictionary<int, int> { { 1, 2 } };
// we can make them invocable so one
// can use the type to create an empty list
var list = int{}(); /* or */ {int}();
// existing array initializer
int[] arr = { 1, 2, 3 };
var arr = new[] { 1, 2, 3 };
// infers an int{}
var list = [1, 2, 3];
// equivalent to
var list = new List<int> { 1, 2, 3 };
// infers a JObject
JObject json = { "foo" : "bar" };
var json = new JObject { "foo" : "bar" };
// equivalent to
var json = new JObject { ["foo"] = "bar" }; In the last example, nested maps will infer the type of the parent, in this case This has some interactions with #2319 so if you want to create another class you should be able to omit type parameters, like KeyedCollection<,> collection = { ... };
SortedList<> list = [ ... ]; If the context already provides type information, such as a function argument or an already typed variable, you can create an empty list or dictionary with By the way, depending on the name of |
What about var other = { "Name" : "Bill Gates", "Age" : 60 }; This couldn't map to |
@bondsbw You can already create a |
@alrz Right, I'm just not sure I like how Preserves type info, but not JSON compatible: var anonymous = new { Name = "Bill Gates", Age = 60 };
int age = anonymous.Age; JSON-compatible syntax but loses type info: var dict = { "Name" : "Bill Gates", "Age" : 60 }; // IDictionary<string, object>
int age = (int)dict["Age"]; // requires cast JSON-compatible syntax that retains type info (I changed the inner Tuples to KeyValuePairs since that seems to be a clearer definition of their purpose): var tuple = { "Name" : "Bill Gates", "Age" : 60 }; // Tuple<KeyValuePair<string, string>, KeyValuePair<string, int>>
int age = tuple.Item2.Value; // no cast required The downside of the last option is that accessing the value via |
@bondsbw Returning a One option is extending IntelliSence to be able to suggest keys with #3555 syntax, var json = { "Name" : "Bill Gates", "Age" : 60 };
int age = (int) json.$Age; But still, you have to explicitly cast the returned
An interface-based solution is proposed but I don't know if that is considered or dropped. PS: If you really want to use tuples you can write var tuple = ( Name: "Bill Gates", Age: 60 );
int age = tuple.Age; and no information shall be lost. |
@alrz You're right, the new Tuple syntax is a lot better than trying to get type safety from JSON literals. As much as I try to advocate for JSON literals, I just don't feel that they are worthwhile. As a language extension (see #6972), JSON literals might make more sense. Not as part of C# proper though. |
@bondsbw Not as "json literals" but as language integrated collection types they would. |
What this request is suggesting is essentially special syntax for instantiating a hierarchical data structure whose values must be of a type specified in a given type collection. In functional programming languages (like F# and Nemerle), this is an extremely common pattern, and is supported through the use of abstract/algebraic data types (particularly the 'variant' or 'discriminated union') and pattern matching (when traversing the data structure). Using the above-specified syntax, could we not infer the types of the dictionary values and generate a DU to encapsulate the set of possible types a value may take? This obviously depends on ADT support becoming part of C# vNext, and I'll try to find the relevant proposal to link to in a bit. Edit: Looking at Nemerle's implementation of variants may be useful, for gleaning implementation ideas. Essentially, variants are implemented as compiler macros which generate an abstract base class, and the range of possible values that the variant may take are nested child classes which inherit from the abstract parent. These nested child classes can be implemented as record types, which allow the author to use them to encapsulate various real values. An implementation similar to this would allow remaining backwards-compatible with older versions of C#, just as Nemerle variants are compatible (though somewhat unwieldly) with current C#. Edit: Here's the relevant ADT proposal I mentioned earlier. |
Please do not make the C# language rely on the presence of a type called |
@gafter
|
@AdamSpeight2008 are you proposing a new keyword? What are its semantics? How would that work in the recursive (nested) case? |
@gafter Yes, and also a bit of clarification on things within yours. :-) The prefix for JSON makes sense as won't have the same grammar rules as C#, like VB's XML Literals. It just indicates a JSON block follows, Within it should follow the grammar rules for JSON. How would you include values from a .net object? other than the literals? var k = "Key";
var v = 42;
var j = json { k : v } ; // <-- ? wanting { "Key" : 42 } Wouldn't this require some form of escaping with the literal? To be useful. var j = json { @{ from entry in dict
where entry.value >= 18
select key
}
}; // Produce a JSON array ot the keys |
@AdamSpeight2008 I like that. And going further, I prefer it be extensible so that the language is not just catering to the flavor-of-the-day. I proposed a similar mechanism in #6972, and despite it being closed I still believe there is room for more than just an analyzer. Syntax highlighting and intellisense could be amazingly useful features for embedded DSLs. Sure, this is all technically possible by customizing Roslyn. But that level of language change makes more sense when you want to fully customize C# by adding keywords, operators, expression types, and other deeply-integrated language features. Customizing Roslyn can also be quite complex, and does not provide a mechanism to embed multiple DSLs from separate sources. Embedding a DSL inside a block is better for non-C# languages like data languages, or when the readability of the concept you want to express is hindered by the C# language. Here is an example of a DSL I would like to be able to embed in C#, such that the result of the expression is transformed into a custom hierarchical data type that recognizes information such as level and section identifiers: Table of Contents
1. Before you begin
2. Introduction
3. Compiler concepts
a. Lexer
b. Parser
c. Checker
d. Emitter
4. Creating your own language
a. Design
b. Optimization
c. Tooling Or perhaps the embedded DSL handler transforms it into a dictionary hierarchy, or whatever. And it can perform syntax highlighting, show syntax errors, provide intellisense, and all of the capabilities you might expect from modern language tooling. C# as-is lacks the readability you could achieve with a DSL that is built for the purpose: new TopLevelNode("Table of Contents",
new SectionNode("1", "Before you begin"),
new SectionNode("2", "Introduction"),
new SectionNode("3", "Compiler concepts",
new SectionNode("a", "Lexer"),
new SectionNode("b", "Parser"),
new SectionNode("c", "Checker"),
new SectionNode("d", "Emitter")
),
new SectionNode("4", "Creating your own language"
new SectionNode("a", "Design"),
new SectionNode("b", "Optimization"),
new SectionNode("c", "Tooling")
)
); |
I am not aware of any suggestion to have it use a "different" grammar. It would be folded into the C# expression grammar. |
@gafter Just that the examples I seen use literals, hence looks like vanilla JSON . |
If you want the value of an expression in there you just write the expression |
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. @AnthonyDGreen has volunteered to champion this feature request. If he does, please provide a link here to the appropriate repo. |
@gafter @alrz @bondsbw @nerdshark |
I saw this after the last comment:
I did not do such thing and I even don't know what it means! |
@MohammadHamdyGhanem so this happens when the person assigned is no longer in the Microsoft github organization. Github unassigns them as soon as there is any change to the issue. |
@jmarolf |
This is a bug on github and it has been reported |
Please extend the syntax for object initializers so that json literals would be valid, and would cause the construction of some representation isomorphic to the json data.
It would be nice if there were some way to indicate which json data structure should be constructed, but obviously that cannot be within the data, as it would no longer be json.
The text was updated successfully, but these errors were encountered: