-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Language support for KeyValuePair<TKey, TValue> struct and tuple mappings #11910
Comments
Similar functionality is explicitly mentioned in the meeting notes here: #11205 However they are looking at much more general purpose syntax which works with existing types rather than defining new forms of operators and the like. Your proposal adds a lot of new language concepts for a rather narrow feature and I don't think it's worth it. |
@HaloFour this narrow feature is a starting point. I suggested general approach completely independent from Tuple and KeyValuePair types. "Tuple mapping" is a similar concept to tuple-like constructors, but it generalize approach and merge it with tuples as it allow not only construction but assignment of existing tuples to variable of any type which support tuple mappings. As for keyed types it's not so "narrow" feature. Key/Value pattern is used massively and currently is tied to KeyValuePair struct. One obvious field of use for keyed types is a SQL-mapped ORM objects as any ORM entity have primary key and used with key in almost any data processing algorithms. Operator overloading is a natural way to handle such features. |
Why would you need new general purpose tuple operators when you could just use the existing implicit conversion operators? public static implicit operator Class2<T1, T2>((T1 field1, T2 field2) tuple)
{
return new Class2<T1, T2>() { Field1 = tuple.field1, Field2 = tuple.field2 };
} The KVP-specific elements of this proposal involve adding some very non-C# syntax to C#. I'm not sure how you propose that those generic members would work given the nature of generics in the CLR. |
@HaloFour because (T1, T2) tuple in this case is a concrete type mapped to |
I suggest approach similar to |
The mapping to an interface constraint isn't enough, you can't dot into a generic type parameter member to ascertain another generic type parameter. public IKeyedDictionary<T, TK, TV> where T : IKeyValuePair<TK, TV> { } It wouldn't be a good idea to automatically expand the arity as |
@HaloFour to avoid implicit interface arity expansion it will be better to define Updated issue thread starting post. |
@HaloFour So, to sum up, on CLR level
If you do not define T.! or T.* type arguments it should be translated to
So you can assign So,
and if you implement other interface
would translate to
If you don't define T.! or T.* type arguments it mean you have no interest in its types and it would default to And another example:
will be translated to
|
@Opiumtm So that would render those syntax changes unnecessary. You're not talking about a situation that occurs frequently enough to justify having to invent completely alien syntax just to save maybe a dozen keystrokes. |
@HaloFour I'm talking about very common and especially painful to use in real code pattern. Key/Value pairs are used in many places including modern Windows Runtime APIs. Keyed objects is used everywhere if object have unique ID. It would add generalized syntax to such keyed objects and key/value pairs. |
Strongly dislike |
@jnm2 |
I think |
I agree. C# is not a symbol-heavy language. Given the amount of backlash for suggesting use of ordinal members for tuple elements I can't imagine that there would be much support for special character identifiers for this one special case, especially special characters already mapped to operators. I am warming to the idea of "tuple-like" conversion operators, but I do think that I would stick to the implicit operator syntax: public static operator implicit KeyValuePair<TKey, TValue>(TKey key, TValue value) {
return new KeyValuePair<TKey, TValue>(key, value);
}
// later
KeyValuePair<int, string> kvp = (123, "foo");
// which is really
KeyValuePair<int, string> kvp = KeyValuePair<int, string>.op_Implicit(123, "foo"); |
@HaloFour It's because you haven't worked on massive data processing.
And so, you shouldn't reference to concrete If you haven't abstract "key" concept, you should write it as
You are forced to add |
Thank you for questioning my credentials. That will certainly lead to constructive conversation on this subject. Your argument is silly. Such small verbosity modifications don't warrant or justify completely rewriting the rules for member or type identifier naming. Manually writing keyed objects or keyed object containers is not a common task, for any style of programming. Typing ONE extra character doesn't slow you, the compiler, or the runtime down in any way that would affect processing data of any quantity. And, given Intellisense, you're not typing that character anyway. So, no, you shouldn't have to reference any concrete member or type member. C# should not become a read-only ASCII sneeze. |
This syntax isn't so clean. public static operator implicit KeyValuePair<TKey, TValue>(TKey key, TValue value) {
return new KeyValuePair<TKey, TValue>(key, value);
} It's not clean because |
In the same way that One interesting thing here, admittedly a bit off main topic, is that @Opiumtm wants to use |
@HaloFour I reasonably question it because you're mentioned that object "key" issue is rare and "narrow". No personal offence. If you're saying it's rare and narrow - I can make assumptions on your typical application code profile 😄
Well, it's quite common for a certain type of apps. That's what I meaning when I have "questioned" your typical app code profile. |
So what do you propose for abstract |
@jnm2 I propose to not use type member name at all. |
I propose not doing anything. Adding such radical new syntax simply so that you can reinvent |
Not reinvent, but avoid it. Well, so verbate code looks much readable if it's rigged by many |
@Opiumtm I don't understand. How is the |
@svick it's more general because it's not a type member and have no name. When you type |
That doesn't make it more general, it just makes it less readable. This proposal doesn't add anything new to the language, it just replaces proper member names with characters. If you want to avoid typing out |
@HaloFour I think verbose syntax often make things less readable. Visual Basic code is definitely less readable than C# code because of its verbosity. And this |
Operators are still type members.
I don't see the difference:
Neither of the two is more general. |
@svick operators are type members only on CLR-level, but not on language level. Same goals can be achieved by defining a generic interface with In particular, ORM libraries does this and each time reinvent their own means to extract entity keys in generic fashion. Entity Framework, for example, have an entity context method to get key from arbitrary entity. |
An unary operator that returns the component result of a calculation on that type is a member as much as any other. However, operators are Also, |
@Opiumtm The MSDN C# Programming Guide disagrees with you, it lists operators among type members. And so does the C# specification (from section Class members):
That sounds like you may want to propose including the |
What's the appeal of having 2-tuples convert to/from KVs rather than having a dedicated syntax for them? e.g. something like |
C# does what it does quite well. The right way to generalize keys and values is at the class library level with an interface, not at the language level. C#'s focus is not primarily Entity Framework or any other keyed data.
But that is exactly how such an interface would prove the worth of the concept in the first place. Failing that, you definitely do not want it as a language feature. An interface in a library provides semantic context; what does |
I assume |
@Opiumtm This sounds like a form of structural typing involving nominal ( If so, there is no gain from making these static, as that precludes constraints, and the member names are irrelevant, so specifying additional non standard symbolic names is not helpful. Basically, this seems like a proposal for structural typing with Some form of typesafe structural typing would be very powerful, so I am sympathetic to the idea but why not make it truly abstract by forgetting |
We intend to support key/value pair support in teh collection literals feature. Thanks! |
KeyValuePair is very often used in C# code in many scenarios.
As there is
(k, v)
tuple syntax support, I suggest same support for KeyValuePair widely used struct.#11530
As KeyValuePair and Tuple is a common pattern and sometimes there is custom Tuples or Keyed structs implemented, I suggest generalized built-in support for such tuple patterns and generalized support for keyed classes/structs at language level.
For such purposes I suggest new overloadable operators.
For tuple mappings (enable tuple-syntax initializing and tuple assignment)
and if class is generic:
This will allow such things:
So,
KeyValuePair<TKey, TValue>
should also support tuple operator and instead ofnew KeyValuePair<string, string>("key", "value")
you can just write("key", "value")
if you're returning KeyValuePair from function, assign it to variable or use it as parameter for method.And for object keys support.
Support for "value" operator
Extract types of keys and values at compile-time
Use types of keys and values in generics
T.!
meaning type of key andT.*
meaning type of valueAnd implicit (or explicit) operator conversion from keyed objects for existing APIs compatibility
Also added
<T>
forimplicit<T>
operator, so implicit conversions can accept generic source object argumentThe text was updated successfully, but these errors were encountered: