-
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
[Proposal] Allow explicit declaration of anonymous types (in local collections) #3304
Comments
Taking constructs added to the language in order to facilitate the functional aspects and forcing them into the imperative syntax doesn't make a lot of sense. There was an imperative solution to that problem long before anonymous types and type inference were added to the language. I think allowing for type inference to be driven by a potential eventual usage is opening an error-prone and confusing can of worms. |
Agree with @HaloFour |
@HaloFour I don't insist on class-level inference, since it will be covered by language-level tuples - updated the post accordingly. Method-scoped anonymous type inference is already present though, it's just not consistent. |
@dimaaan I never said that. I use different approaches based on the problem at hand. Cramming everything into LINQ is not always a good idea. |
@dsaf look at following code private void NewSyntaxSample()
{
var r = new Random();
// Using a suggested keyword, type inferred from first usage below.
var list = new List<anonymous>();
if(r.Next() % 2 == 0)
{
list.Add(new { Id = 1, Name = "Specimen #1" });
}
else {
list.Add(new { Id2 = 1, Name2 = "Specimen #2" });
}
// How do i access list member??
} |
@dimaaan This is not how anonymous types generally work. Consider the following example demonstrating your code rewritten using today's C#: private void DoesntWorkAlready()
{
var r = new Random();
var list = Enumerable
.Range(0, 10)
.Select(i => new { Id = i, Name = "Specimen #" + i });
if (r.Next()%2 == 0)
list = list.Concat(new[] {new {Id = 100, Name = "AAA"}});
else
list = list.Concat(new[] { new { Id2 = 100, Name = "AAA" } });
// The line above will give you an error ^.
} |
Only based on the immediate usage. Given assignments are right-to-left the compiler already knows the exact type at the point of inference. This would require that the compiler not know the type until some indeterminate point.
Only because the compiler already knows the type based on the assignment to |
@HaloFour I am inclined to agree now, after some consideration. Can you think of any other alternative? How about this: var list = (new[] {new {Id = -1, Name = "[ignored]"}}).Skip(1).ToList(); vs var list = new List<new {int Id, string Name}>(); // Anonymous, yet specified immediately. It does look more and more like tuples though... |
Looks better now |
@dimaaan That might work in Java due to type-erasure, but it suffers from the same exact problem at above in C# because the type of the generic type parameter isn't known and it must be known in order to complete the type and instantiate it. There is no |
@HaloFour Well, a language-level |
Technically if you care about the potential allocations, you could write a helper [MethodImpl(MethodImplOptions.AggressiveInlining)]
static List<T> CreateListForAnonymous<T>(T dummy)
{
return new List<T>();
}
...
// then later when you use it.
var mylist = CreateListForAnonymous(false ? new {Id = 0, Name = ""} : null) This is awful but at least then you're not instantiating the object. The compiler will simplify that method invocation as |
@dsaf IIRC that's just C# syntax specifically related to creating |
@mburbea I am more worried about readability than performance, but yes that is a clever trick. It would be nice to avoid having to create new adhoc classes or using library-level tuples when writing local imperative code. |
@dsaf That it can, when it knows what It amazes me how much unreadable mess developers are willing to write in order to avoid even the slightest boilerplate. A nested tuple/class is infinitely more readable. Messy tricks of inference should be avoided wherever possible. If the intention cannot immediately be understood it already costs more than being explicit. Any given piece of code will be read by a human significantly more often than it will be written, it is that first cost that should be minimized as much as possible. |
I mean this feature increase complexity of language, but gives no profit |
@dsaf I view the proposed C# 7 tuples as pretty much a replacement for anonymous types (I doubt a language designed from scratch would have both). Is there any reason why you couldn't use a tuple instead of an anonymous type here? You mention that tuples are "library-level". Is there anything specific about them that makes them unsuitable at a method level? |
if c#7 tuples are |
@svick When I said "library-level" I meant today's |
@dimaaan, I'm the first in favor of a functional style, but I'm agree with @dsaf about consistency (of two styles) and the need of being able to handle anonymous type with easy also when using imperative paradigm. Sometimes right in favor of defining a method that adheres to functional paradigm from the outside, you may need more imperative flexibility from the inside (e.g. to handle mutation). For example even a F# (multiparadigm but mainly functional) implements About syntax, even if I'd like to see new keywords only when absolutely necessary, I think that what suggested at the end of first post is readable and autoexplicative. |
I think this "problem" can be solved by making type inference a bit "better". Compiler could see that you are creating a generic
I am using wildcard character ( Personally I think it would be nice, because it's not only for using anonymous types but for also for other named types. So I could just avoid unnecessary typing that doesn't add much value to comprehend program logic and flow. But I guess this feature doesn't add much value for given costs of development, so I don't have much hopes for this ;) |
@mpawelski, |
"Better" is very relative. I'm personally not a fan of having type inference have to read through the remainder of the method to try to determine how the type will be used. It's more confusing to anyone who has to read and maintain that code. |
@HaloFour Yes, it's very relative and subjective. Just like whole usage of implicit typing. Some people still don't like that we have something like When you say that
it reminds me that it's exactly what people were talking then |
It is all relative. I'm not opposed to some type inference. I like Deferring the type inference based on usage complicates those rules and makes the developer have to keep additional things in mind when reading the code. It also introduces edge cases which would need solid rules, e.g.: public class Baz { }
public class Foo<T1> {
public void Bar<T2>(T2 value) where T2 : T1 { }
}
...
var foo = new Foo<*>();
foo.Bar(new Baz()); // legal? If so, what is T1 or T2? It's all a scale. The sweet spot is somewhere in the middle and different for everybody. |
|
|
You probably want tuples (#347). |
@gafter I guess, as long as fields/properties can definitely be named. Does it mean anonymous types will be "outdated"? |
They "can't". They still have usages. Tuples won't have names outside of the source code. So, they won't be bindable. With enough work, the names could be put in expression trees for queriables, but does it worth the work, given that anonymous types already exist? |
@paulomorgado for relevenat discussion see #6877. Since tuples are value types and going to be more common to be used with LINQ I think it does. |
@alrz, I'm aware of that discussion. But, while you think we can get rid of anonymous types, I think we can't. |
If they get interfaces #13 they might become more interesting. But it feels like tuples will be preferable where possible. Of course you cannot get rid of anonymous types, they will just be rarely seen just like |
@dsaf I think so. Unless you really want a reference type; assuming that expression trees support tuples, I can't think of any other use cases that you might prefer anonymous types over tuples. |
We are now taking language feature discussion on https://github.com/dotnet/csharplang for C# specific issues, https://github.com/dotnet/vblang for VB-specific features, and https://github.com/dotnet/csharplang for features that affect both languages. |
C# thrives on being a multi-paradigm language. One of those paradigms is the imperative one, which is useful in some scenarios depending on personal preferences.
However it seems that there are some discrepencies between general feature availability in imperative and functional paradigms in C#.
One of such features is anonymous types. While it is easily possible to create a list of anonymous instances via functional paradigm (LINQ monad), it's not that easy to create same list in an imperative way.
Please find comparative examples below.
Functional:
Imperative:
This is obviously a pain point:
http://stackoverflow.com/questions/15749445/is-there-a-trick-in-creating-a-generic-list-of-anonymous-type
http://stackoverflow.com/questions/612689/a-generic-list-of-anonymous-class
The issue could be looked at in a bigger picture, e.g. class-level local inference of anonymous types (limited to private members, e.g. would allow returning an explicitly anonymous type (as opposed toobject
) from a type's private methods.Suggested syntax could be something like:
The text was updated successfully, but these errors were encountered: