Discussion: Anonymous struct types #2551
-
Discussion: Anonymous struct typesSummarySupport anonymous struct types. Specifically, allow anonymous type derives from value type. MotivationAnonymous types are applied anonymous naming but fully structured class type. Detailed designStandard anonymous types syntax: // It's standard anonymous types. (Derived from System.Object)
var foo = new { Bar = 123, Baz = "ABC" }; Anonymous struct types syntax: // It's anonymous struct types. (Derived from System.ValueType)
var foo = new struct { Bar = 123, Baz = "ABC" }; And I'm thinking it'll enable by default for C# future release with apply syntax context switch likely nullable reference type: #anonymous struct // The pragma naming is for example.
// It's anonymous struct types.
var foo = new { Bar = 123, Baz = "ABC" };
// It's standard anonymous types.
var foo = new class { Bar = 123, Baz = "ABC" }; (And include enabler in csproj property) It'll not make compatibility issue between objref type and value type because the specification apply only inside for a method body DrawbacksIt'll cause problem in corner case if use it in explicitly objref knowledge: // It's standard anonymous types.
var foo = new { Bar = 123, Baz = "ABC" };
var bar = foo;
Debug.Assert(object.ReferenceEquals(foo, bar)); The code fragment raise assertion error if switched to enable anonymous struct types. AlternativesI'll withdraw it if value tuple's problem fixes in the future. |
Beta Was this translation helpful? Give feedback.
Replies: 22 comments
-
What are the use cases where all of the following conditions apply?
There certainly are cases where one or two of those conditions are true, but I think all three need to be true often enough to make this a worthwhile feature. Also, I'm fairly certain |
Beta Was this translation helpful? Give feedback.
-
I don’t see how making it a struct helps in the slightest. You can’t avoid the allocation when reflection requires boxing your struct to object anyway. |
Beta Was this translation helpful? Give feedback.
-
@yaakov-h You can avoid the allocation, if you don't use reflection directly, but instead use it together with |
Beta Was this translation helpful? Give feedback.
-
@svick but then you have to allocate those... |
Beta Was this translation helpful? Give feedback.
-
@yaakov-h sure, but just once :) That's the kind of thing that static constructors on static generic classes are tailor made for, or lazy initialized static fields. |
Beta Was this translation helpful? Give feedback.
-
On the flip side, if anonymous structs were added, they could always be retrofitted to replace the current value tuple. To keep things backwards compatible, the compiler could still emit the I don't know the full history behind the value tuple implementation choices, but there's likely some reason that the current approach was taken -- using only metadata attributes to record the tuple property names rather than emitting unique structs. If the unique structs had been implemented, the compiler could have emitted an implicit conversion operator to a standard unnamed ValueTuple. It seems like compiler generated anonymous structs could have been a viable choice at the time (I'm sure I'm missing something). The compiler could even have emitted an implicit conversion in the other direction as well to enable duck typing: as long as the definitions match, why not? (obviously using just metadata and ValueTuple likely results in smaller DLLs -- maybe that was a large factor in the rationale) |
Beta Was this translation helpful? Give feedback.
-
To allow sharing. Otherwise, every use of a tuple within assembly would result in generating new and incompatible structs. One assembly would not be able to pass an It's also because of this that it would be impossible to retrofit anonymous structs onto tuples. |
Beta Was this translation helpful? Give feedback.
-
Is that the only reason? Seems quite weak... If the compiler would have emitted the implicit conversion operators to and from the raw In the same manner, anonymous classes could also received implicit conversion operations to/from The order the properties are defined would dictate which Item slot the property value would be assigned to. |
Beta Was this translation helpful? Give feedback.
-
The only gap is the duck typing scenario where named tuple A can currently be converted to named tuple B because they are both actually That problem could have been solved by allowing the compiler to automatically generate duck type conversion code to convert between anonymous named tuples and There might be some performance drawback to that conversion scenario compared to the chosen implementation, which has zero conversion cost (because there isn't any conversion). So that could also have been a reasonable justification. |
Beta Was this translation helpful? Give feedback.
-
https://github.com/dotnet/csharplang/blob/master/meetings/2015/LDM-2015-02-11.md#type-equivalence There's also the question of speakability. What do you call a generated tuple type? If you expose it publicly, it needs a predictable name, and the method of generating that name must be in the spec. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour same problem applies to anonymous classes, right? And those got a naming convention. |
Beta Was this translation helpful? Give feedback.
-
I would have been perfectly fine with duck typing on anonymous named tuples as generated types -- in contrast to the LDM notes:
Nice thing about making them generated types would have been implicit support for seeing the named properties in other languages or older C# compilers. Oh well. But I would love to see named tuples retrofitted and upgraded to full fledged anonymous structs in the future, and have those become the new de facto super named tuples -- caveat: unless there was some really good runtime reason not to. I realize that would be a fair bit of work, so I'm not expecting it to happen. But if it did, it would make life easier in many scenarios. Not the least of which would be enabling reflection based serialization frameworks. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour as for what to call them, I would suggest just calling them anonymous structs. And I would suggest that they be implicitly convertible to Having symmetry for both anonymous structs and anonymous classes would complete the conceptual framework to make this all coherent and intuitive. Simply stated: anonymous types can be treated as tuples, and tuple value order will be the same as the order of the values assigned in the anonymous type instantiation. BTW, thanks for the link! |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Anonymous classes have no visible type signature. You cannot have a method that accepts or returns an anonymous type. It can pass around an object of that type, but only as There is no public/fixed naming convention because they are not visible anywhere that a name is required. |
Beta Was this translation helpful? Give feedback.
-
Thank you for all, I was able to organize my own thoughts. The idea's trigger was problem from Newtonsoft.Json's serialization issue. // Got nothing
var (firstName, lastName) = JsonConvert.DeserializeObject<(string firstName, string lastName)>(
@"{'firstName':'Kouji','lastName':'Matsui'}"); But it causes failure storing each properties. I understand what problem for naming extraction from tuples. I retired to use tuple in this situation, try to change anonymous type rather than tuple type: public static T Deserialize<T>(string json, T defaultValue)
{
try
{
return JsonConvert.DeserializeObject<T>(json);
}
catch
{
return defaultValue;
}
}
static void Main(string[] args)
{
var result = Deserialize(
@"{'firstName':'Kouji','lastName':'Matsui'}",
new { firstName="", lastName="" });
} It's bit ugly but perfect work (allocation cost only used for defaulted value. but the code isn't important and isn't focused). We wrote a lot of anonymous types in the C# 6 or less versions. I was thinking continue:
Afterall. I understanded it constraining by No.2 topic. I think that this problem has not been solved and will not be solved in the future. (So I wrote alternatives section :) |
Beta Was this translation helpful? Give feedback.
-
@yaakov-h you're technically correct, but I think that's speaking past my point. If I were to declare an anonymous tuple/struct like so, Anytime I had a method that accepted a Value tuples could have been implemented that way. And I think that would also achieve the goal of anonymous structs. Moreover, it would be nice if anonymous classes behaved the same way and were implicitly convertible to/from For instance, having anonymous structs and anonymous classes be implicitly convertible to/from In other words, although @kekyo is talking mostly about serialization, I see this as being applicable to a larger class of problems. Again, I doubt this will happen any time soon, and probably not at all. It would be nice though. |
Beta Was this translation helpful? Give feedback.
-
@yaakov-h TLDR version: the anonymous struct / tuple definition would be a stand in for a typename name. Just as it currently is. |
Beta Was this translation helpful? Give feedback.
-
You can't have a randomly generated type name. You need a predictable type name, that will always be the same, regardless of the compiler. That means that the name needs to be in the specification and the compiler needs to carefully adhere to the specification. Otherwise tuples can simply never cross assembly boundaries, thus can never be exposed from a public API. Also, using implicit conversion between The design of tuples was settled years ago and I severely doubt that they're willing to reconsider their decision especially given that every single one of these points was mentioned and addressed. Tuples are intentionally positional ephemeral constructs, not intended for persistence. The names exist only to aid the developer in referencing the elements. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour of course a random type name would be a genuinely bad idea. I was trying to use an emphatic hyperbole to illustrate that I wouldn't care what the name was. Your point is well taken, and my first suggestion was to use a deterministically derived name.
I did mention above that if there was a significant, demonstrable runtime cost to this method, that it wouldn't work. That's an empirical question though, and I don't know how to guess at its answer without taking a stab at it. Moreover, there might be some clever trick to obtain better performance once the implementation is at least in a working state. As you say, it might not have legs at all. Was a scenario like that ever tested and benchmarked by the CLR/C# team? If the JIT was smart about duck typing and the types were immutable, I have a strong suspicion that all of the copying could be eliminated a la
There's another good point on the surface, but again I think if the JIT was smart about how the duck typing was implemented, I think it wouldn't be an issue for the C# compiler to manage.
Alas, I lamentably agree that bit completely. So here I'm describing a C# language feature that probably would require a major assist from the JIT/CLI teams, and that probably won't happen. Too many moving parts. |
Beta Was this translation helpful? Give feedback.
-
@marksmeltzer I feel these features looks like charming for me, but has trade off for difficult topics. I predicted (but couldn't clearly) it, so my proposal isn't containing how enlarge exposing anonymous (class|struct) types outside the method. |
Beta Was this translation helpful? Give feedback.
-
I think better value tuple convert to anonymous struct |
Beta Was this translation helpful? Give feedback.
What are the use cases where all of the following conditions apply?
struct
is too cumbersome.There certainly are cases where one or two of those conditions are true, but I think all three need to be true often enough to make this a worthwhile feature.
Also, I'm fairly certain
#anonymous struct
is not going to happen. C# has been very hesitant to introduce dialects and while#nullable enable
in C# 8.0 does that, that's for the "billion dollar mistake", not a small feature like this one.