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

JSON-Style initializer syntax for dictionaries #2247

Closed
ghost opened this issue Feb 19, 2019 · 34 comments
Closed

JSON-Style initializer syntax for dictionaries #2247

ghost opened this issue Feb 19, 2019 · 34 comments

Comments

@ghost
Copy link

ghost commented Feb 19, 2019

JSON initializer for dictionaries
I suggest to make use of JSON syntax to make dealing with string dictionaries easier and less error prone.
At First, suppose we have this Dictionary:

class JSON<TValue>: Dictionary <string, TValue>
{
}

This JSON dictionary has string keys, so we can write this special syntax to initialize it:

var StdGrades = new JSON<int>()
{
   Adam:  90,
   John: 60
};

The special syntax using : grantees that the names at the left hand are the string keys, not names of variables, So, that syntax is the shorthand of:

var StdGrades = new JSON<int>()
{
   ["Adam"]=  90,
   ["John"]= 60
};

This special syntax also is useful to tell the Intelligence that these key names can be used as if they properties of the JSON object:

Console.WriteLine(StdGrades.Adam);
StdGrades.John = 70;

If the compiler found that StdGrades has no properties with the names Adam and John, then it will check if these names are defined keys in the JSON initializer, so it can translate that code to:

Console.WriteLine(StdGrades["Adam"]);
StdGrades["John"] = 70;

The most benefit of this, is to provide intellisense to auto-complete the key names, so prevent typo mistakes, which are treated as new keys!

Note: This is also applied to VB, either with the . syntax or with the ! syntax.

Finally: JSON object will not be dynamic, so , we can't add new keys with the . syntax, because this will revert us back to the possible typo mistakes. New keys can only be added by the indexer syntax, or if they are will known from the start, they should be added in the JSON initializer.

Note:
Expando object can be use the same intializer to add some of intelligence for the dynamic properties.

var StdGrades = new ExpandoObject()
{
   Adam:  90,
   John: 60
};
@HaloFour
Copy link
Contributor

dotnet/roslyn#6949

C#'s existing initializer syntax is completely agnostic to the data type in question. Collections with an Add method that takes multiple arguments can be called as follows:

var StdGrades = new JSON<int>()
{
   { Adam, 90 }
   { John, 60 }
};

Collections with an initializer can be called as you described.

To add your syntax would mean a third syntax which seemingly takes a hard dependency Dictionary<TKey, TValue>.

@ghost
Copy link
Author

ghost commented Feb 19, 2019

@YairHalberstadt
Lets discuss the concept. It it's approved, we can discuss implementation details.

@HaloFour
The purpose is not to get a new syntax for just adding new syntax. The currently two syntaxes can be used, but they are longer, and we can't get rid of the "" because the string will be considered a variable name. Moreover, the quotations will allow user to use spaces and unhallowed maypoles. The JSON syntax is perfect for my purpose.

@YairHalberstadt
Copy link
Contributor

I think there's a seperate issue here which may be relevant, which is intellisense for dynamic objects.

Using Roslyn with some sort of attribute language to indicate that a parameter to this method is the name of a property might make for an interesting experiment. It would be similar to the nullable flow analysis and associated attribute language API.

@ghost
Copy link
Author

ghost commented Feb 19, 2019

@HaloFour

var StdGrades = new JSON<int>()
{
   { Adam, 90 }
   { John, 60 }
};

You will have errors because no Adam and John variables in context. You can't change this behavior because it will break existing code. So, you must use:

var StdGrades = new JSON<int>()
{
   { "Adam", 90 }
   { "John", 60 }
};

and this can allow:

var StdGrades = new JSON<int>()
{
   { "Adam Smith", 90 }
   { "John,!", 60 }
};

Which can't be used as properties names.
So, instead making too much roles, it is easier to use the will known JSON syntax.

@HaloFour
Copy link
Contributor

@MohammadHamdyGhanem

I am not moving this particular issue because I don't have confidence that the LDM would likely consider doing this.

The concept has been discussed.

@ghost
Copy link
Author

ghost commented Feb 19, 2019

@YairHalberstadt
I myself posted many proposals regarding the same issue, including allowing initialization of ExpandoObject. But I am interested generally of string dictionaries, because they are widely used and the ExpandoObject is a special case of them.

@ghost
Copy link
Author

ghost commented Feb 19, 2019

@HaloFour

The concept has been discussed.

This is a new angle :)
For example, this is how I propose to write string values:

var foo= new JSON<string>()
{
   itm1: "test 1",
   itm2: "test 2" 
};

There the syntax uses "" for both keys and string values! This doesn't fit the purpose of my proposal.
once again: look at the gain. I don't want JSON syntax for itself. But it fits will for my purpose. So, please re-consider this. The context is different, so be dynamic not static :)

@HaloFour
Copy link
Contributor

JSON requires that keys be strings. If they're not strings you get into the whole mess of what is a valid identifier and how do you escape invalid identifiers. JavaScript has a long list of reserved keywords which would make illegal identifiers. C# has a different list of reserved keywords.

So, your flavor of the existing considered, prototyped and rejected proposal is considerably worse.

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Feb 19, 2019

and this can allow:

var StdGrades = new JSON<int>()
{
  { "Adam Smith", 90 }
  { "John,!", 60 }
};

Which can't be used as properties names.

Why not? Both of those are totally legal json property names:

image

I should know. I wrote the json LS support for both TypeScript and Roslyn :)

You can read the relevant RFC here: https://tools.ietf.org/html/rfc8259#section-4

Specifically, an object member is simply: member = string name-separator value

So, any json-string is the only thing allowed as a member name in json.

@CyrusNajmabadi
Copy link
Member

The most benefit of this, is to provide intellisense to auto-complete the key names, so prevent typo mistakes, which are treated as new keys!

You don't need a language feature for this. You could just write a Roslyn completion provider that provides better intellisense for Json.net interactions.

@ghost
Copy link
Author

ghost commented Feb 19, 2019

@HaloFour @CyrusNajmabadi
I am speaking about JSON style not porting JavaScript JSON with its javascript roles to C#. Sorry I am not aware that you got it this way. Of course I want to apply C# and VB variable declaration to the Key names to be allowed in this JSON-Style syntax.
I already explained why intellisense can't be easily done with current intializer syntax that uses quotes. Dealing with unvalid variables names is hard, and will complex things. Besides, JSON Style syntax is the shortest one.

@ghost ghost changed the title JSON initializer for dictionaries JSON-Style initializer syntax for dictionaries Feb 19, 2019
@HaloFour
Copy link
Contributor

@MohammadHamdyGhanem

I am speaking about JSON style not porting JavaScript JSON with its javascript roles to C#. Sorry I am not aware that you got it this way.

Besides, JSON Style syntax is the shortest one.

There's no reason to have yet-another-style, and this is not a race to see how short if could possibly be. You can't possibly wade into using identifiers for string keys without dealing with the problem with identifiers.

I already explained why intellisense can't be easily done with current intializer syntax that uses quotes.

No you didn't. Intellisense can certainly be improved to allow autocomplete of indexers. It would be quite literally the same work in order to enable autocomplete of these "pseudo-members".

Also, dotnet/roslyn#3555

@CyrusNajmabadi
Copy link
Member

I am speaking about JSON style

I don't know what that means.

I already explained why intellisense can't be easily done with current intializer syntax that uses quotes.

I don't know what that means. TypeScript supports json objects, and has no problem with complex names like "John,!". For example:

image

@CyrusNajmabadi
Copy link
Member

@MohammadHamdyGhanem Your very first sentence says this:

I suggest to make use of JSON syntax to make dealing with string dictionaries easier

If you want to make working with a string-dictionary easier, then your solution better handle all strings that could go in a dictionary.

@ghost
Copy link
Author

ghost commented Feb 19, 2019

@CyrusNajmabadi
JavaScript has some rules to convert CSS names to valid properties names, for example: border-width becomes borderWidth. Something like that can be done with unvalidkeys, (Adam Smith -> Adam_Smith, or AdamSmith) but I don't like this idea, becuase the whole purpose is to make things easier for the developer.

@HaloFour
Copy link
Contributor

@MohammadHamdyGhanem

JavaScript has some rules to convert CSS names to valid properties names,

That has nothing to do with the language JavaScript or the JSON format.

@CyrusNajmabadi
Copy link
Member

becuase the whole purpose is to make things easier for the developer.

Easier in what way? Currently, you've only mentioned intellisense. But that's something you can improve upon without needing to change the language.

@ghost
Copy link
Author

ghost commented Feb 19, 2019

@CyrusNajmabadi
Many asked for that improvemnet and it didn't happen, which made me feel there is a problem!

@CyrusNajmabadi
Copy link
Member

Many asked for that improvemnet and it didn't happen

Be the change you want to see in the world :) If you want this to happen, feel free to contribute a PR. I'm happy to help advise you on how to get it done. But changing the language in order to get better intellisense is not really going to go anywhere. It'll be roughly 1000x more expensive than just making the PR to improve intellisense itself.

@Thaina
Copy link

Thaina commented Feb 20, 2019

I don't think it worth to implement this

var StdGrades = new JSON<int>() {
   Adam:  90,
   John: 60
};

Just for cutting a little [" and "]

var StdGrades = new JSON<int>() {
   ["Adam"] = 90,
   ["John"] = 60
};

Which is already work, and much more versatile. It could work with not only JSON but also any kind of dictionary. And also it could take variable value, not just constant, with the one syntax. Your proposal is not general enough to be worth as a syntax

And what will happen to this below code?

var StdGrades = new JSON<int>() {
   Count: 90
};

@ghost
Copy link
Author

ghost commented Feb 20, 2019

@Thaina

just to

No, please read the rest of the proposal

This special syntax also is useful to tell the Intelligence that these key names can be used as if they properties of the JSON object:
Console.WriteLine(StdGrades.Adam);
StdGrades.John = 70;
If the compiler found that StdGrades has no properties with the names Adam and John, then it will check if these names are defined keys in the JSON initializer, so it can translate that code to:
Console.WriteLine(StdGrades["Adam"]);
StdGrades["John"] = 70;

@Thaina
Copy link

Thaina commented Feb 20, 2019

@MohammadHamdyGhanem This is not related to the intellisense at all. We could just create smart intellisense that will populate possible value on indexer instead. And what you want is more like intellisense for dynamic which is already proposed dotnet/roslyn#15974

Dictionary is not dynamic and should not be overlapped by syntax

@ghost
Copy link
Author

ghost commented Feb 20, 2019

@Thaina
All that were said and discussed above. This is for string dictionarirs only, which expandoobject is one of them. I want to treat the JSON class as semi dynamic but for keys added to the intitializer only. It is still static but expose intial keys as if they are properties, so that they are strongly typed in a shorten syntax.

@ghost
Copy link
Author

ghost commented Feb 20, 2019

And one gain over expando object, is that we can definr the type of the values rather than being objects.

@CyrusNajmabadi
Copy link
Member

No, please read the rest of the proposal

This special syntax also is useful to tell the Intelligence that these key names can be used as if they properties of the JSON object:

I already showed how intellisense can understand and support full string keys. I literally implemented that for TypeScript. That was in this post: #2247 (comment)

:)

As mentioned above, if you want intellisense to be improved, there are ways you can already do that today. I'd be happy to walk you through the process if you're interested. However, no language feature is needed for this currently.

@ghost
Copy link
Author

ghost commented Feb 20, 2019

@CyrusNajmabadi

if you want intellisense to be improved

I want to access the keys by the dot notation syntax (StdGrades.John instead of StdGrades["John"]). It is strange to have this in a preemptive script language like JavaScript, but not in higher level languages Like C# and VB.NET. The ! symbol in VB.NET is some sort of a solution, but keys are still not strongly typed, and I don't like this strange ! symbol!

@CyrusNajmabadi
Copy link
Member

I want to access the keys by the dot notation syntax

given that strings can contain far more allowed data than what is legal for an identifier name, your proposal seems far too limiting given the expressly stated goal of:

I suggest to make use of JSON syntax to make dealing with string dictionaries easier and less error prone.

It is strange to have this in a preemptive script language like JavaScript, but not in higher level languages Like C# and VB.NET

I don't see anything strange about that.

and I don't like this strange ! symbol!

The language isn't going to change just because you don't like some piece of syntax.

@ghost
Copy link
Author

ghost commented Feb 21, 2019

given that strings can contain far more allowed data than what is legal for an identifier name

According to my proposal, they can't! This is why I proposed to have a special string-key generic value dictionary. If the name JSON cinfuses you, give it any other name. My focus is on the idea. JSON is the source where I got the idea, but this proposal is not about copying JSON as it is to .NET.

The language isn't going to change just because you don't like some piece of syntax.
Language change everyday according to what developers like and dislike. Every language has some deserted features, left there for backward compatability. I myself don't use the ! lookup operator becuase it doesn't feel right in VB syntax (StdGrades!John)! VB could use the . instead, and still get the true meaning.

@HaloFour
Copy link
Contributor

@MohammadHamdyGhanem

According to my proposal, they can't!

You can't stop it.

void AddBad<T>(T dict) where T : IDictionary<string, int> {
    dict.Add("bad identifier!", 123);
}

var json = new JSON<int>();
AddBad(json);

The definition/rules for identifiers changes between every language.

Language change everyday according to what developers like and dislike.

Only if there is consensus that the change is a considerable improvement, especially to justify the exorbitant cost that goes into changing the language.

Every language has some deserted features, left there for backward compatability.

How many such features exist in C#? Language design is exceptionally conservative specifically for this reason.

This kind of language feature was already considered for C# 6.0. It was roundly rejected on the basis that it added nothing worthwhile to the language and the problem of discovery of keys via Intellisense could be solved in more universally applicable ways.

I myself don't use the ! lookup operator becuase it doesn't feel right in VB syntax (StdGrades!John)! VB could use the . instead, and still get the true meaning.

No it couldn't, they two mean different things:

Imports System
Imports System.Collections.Generic

Module Program
    Sub Main()
        Dim d As New Dictionary(Of String, Integer)
        d.Add("Count", 123)
        Console.WriteLine(d.Count) ' prints 1
        Console.WriteLine(d!Count) ' prints 123
    End Sub
End Module

@ghost
Copy link
Author

ghost commented Feb 21, 2019

@HaloFour
The predefined keys are those written in JSON intialization. This is what I said from the start:

JSON object will not be dynamic, so , we can't add new keys with the . syntax, because this will revert us back to the possible typo mistakes. New keys can only be added by the indexer syntax, or if they are will known from the start, they should be added in the JSON initializer.

This is a quick alternative to defining these keys and values as resources.

@HaloFour
Copy link
Contributor

@MohammadHamdyGhanem

So trying to add to the dictionary would then throw at runtime? What's the point then? Use an anonymous type.

@ghost
Copy link
Author

ghost commented Feb 21, 2019

@HaloFour
No, it is a normal dictionry.
Can you use the `!' operator in VB.NET with any key, or just with keys that don't contain spaces and symbols?
My point is: this is just a way to ease writting code in most cases but not all of them.

@HaloFour
Copy link
Contributor

@MohammadHamdyGhanem

No, it is a normal dictionry.

Which means people can add invalid keys to it after the fact, as I said.

Can you use the `!' operator in VB.NET with any key, or just with keys that don't contain spaces and symbols?

Only with keys that are valid identifiers, otherwise you have to resort back to the normal property syntax. This is exactly what makes it almost completely pointless. The ! operator in VB.NET is a legacy holdover from VB, and it wasn't all that commonly used then either because it obfuscated what you were trying to do and provided no actual benefits.

My point is: this is just a way to ease writting code in most cases but not all of them.

It doesn't help write code. It makes a very narrow case very slightly less verbose.

This was already proposed and was already rejected.

@YairHalberstadt
Copy link
Contributor

CLosing as the OP is no longer on github, and this was fairly poorly received

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants