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

C# feature idea: Using 'new' without the type name to call constructors #4413

Closed
e-master opened this issue Aug 7, 2015 · 25 comments
Closed
Labels
Area-Language Design Resolution-Duplicate The described behavior is tracked in another issue

Comments

@e-master
Copy link

e-master commented Aug 7, 2015

Taken from: https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/9216582-using-new-without-the-type-name-to-call-construc

Similarly how the var keyword makes it simpler to declare an object in C#, the new keyword could also imply the type/constructor to be used to initialize an object.

For example:

// instead of writing:
Dictionary<string, List<Tuple<int, int>>> data = new Dictionary<string, List<Tuple<int, int>>>();
// one could write simply: 
Dictionary<string, List<Tuple<int, int>>> data = new();

The compiler would be able to match constructor overloads as well, so potentially you could do the following:

// instead of writing:
StringBuilder data = new StringBuilder("test data", 1000);
// one could write:
StringBuilder data = new("test data", 1000);

This feature might be useful in list initializers too, e.g.:

List<StringBuilder> builders = new() 
{ 
  new("builder1-data", 100), 
  new("builder2-data", 100), 
  new() 
};

And contrary to var it could be used in class member initialization.

@NaxAlpha
Copy link

NaxAlpha commented Aug 7, 2015

It would be good idea

@whoisj
Copy link

whoisj commented Aug 7, 2015

this is nice for unwieldy long generic declarations

@paulomorgado
Copy link

Also for method parameters;

M(new());

@HaloFour
Copy link

Feels a little backwards given the usual direction that inference generally happens in C#. Having some form of shorthand for situations where you can't use var would be appreciated, though.

@dsaf
Copy link

dsaf commented Aug 11, 2015

@paulomorgado it can easily be abused in such scenarios. The fact that the method name is completely undescriptive makes that example even worse. There is no way I can tell what that new() argument is.

My personal preference is to even include the argument name:

M(customerAccount: new Account());

@paulomorgado
Copy link

@dsaf, the cryptic example is intentional.

If you don't know what M does, it's parameter type is of no use to you. M(customerAccount: new Account()); is no more readable that M(new Account()); or even M(new());.

The biggest problem is the understanding by developers of method overload resolution criteria. But for simple cases, it reduces ceremony.

Take the example of XmlReader.Create(string, XmlReaderSettings), wouldn't this be nicer?

XmlReader.Create("path to file", new { ValidationType = ValidationType.Auto });

Would adding the type (XmlReaderSettings) really make it more readable?

I know that syntax clashes with anonymous type instantiation. But there's not overload for that method taking a string and a type compatible with an anonymous type, so there's no collision there. Just more spec and compiler work.

@dsaf
Copy link

dsaf commented Aug 12, 2015

Take the example of XmlReader.Create(string, XmlReaderSettings), wouldn't this be nicer?
XmlReader.Create("path to file", new { ValidationType = ValidationType.Auto });

It most definitely would not be nicer, but this is just my opinion. I cannot tell whether it's XmlReaderSettings or XmlFileCreationSettings or FormatDiskCAndDropMasterDbInvoker and I do care which one it is.

@paulomorgado
Copy link

It most definitely would not be nicer, but this is just my opinion. I cannot tell whether it's XmlReaderSettings or XmlFileCreationSettings or FormatDiskCAndDropMasterDbInvoker and I do care which one it is.

I used to be like that - hate var and such. 😄

It's XmlReaderSettings because it couldn't be anything else.

ASP.NET MVC is full of anonymous types used by convention, which is a lot worst, I think.

@TyreeJackson
Copy link

I could see using this in some situations. Like everything else, context matters. Sometimes I use named parameters in method calls, sometimes I don't. And sometimes I could see using this in either a method call or especially in some object initializers. Nice idea @e-master.

@e-master
Copy link
Author

Thanks @TyreeJackson! It's really nothing extraordinary, just came up when I had to write a long initializer for a class member, and I got somewhat upset about the redundant constructor call.

The one thing I like about this feature is that it is pretty intuitive - any C# developer would get used to it very quickly.

I can see the point @dsaf is making - I wouldn't like to start working on someone's code if it's full of calls like M(new()), especially if I am new to the API. I am more inclined to consider it a drawback than a benefit of this feature, but it's not all that bad, and in some cases I agree with @paulomorgado because:

  1. Believe it or not, many developers like to read/write short code, even if at times it may seem somewhat ambiguous. At the end of the day, our modern IDEs make it easy to clarify any confusion by simply moving the mouse over the keyword. I for one prefer @paulomorgado's example with the XmlReader.
  2. If you have a developer writing production code like M(new()), i can guarantee you that this will be only one of the many stylistic mistakes he/she will make :-)

My take on it is that it would be a useful feature and not more harmful than var - if used responsibly it would improve developer productivity.

@dsaf
Copy link

dsaf commented Aug 13, 2015

@paulomorgado

I used to be like that - hate var and such. 😄

No need to be patronizing. I use var all the time, it does not have the problem I am talking about.

It's XmlReaderSettings because it couldn't be anything else.

It's not a matter of inference implementation. As a human, until you familiarize yourself with the API or use an IDE feature - it can be anything.

@e-master

Believe it or not, many developers like to read/write short code, even if at times it may seem somewhat ambiguous...

Yeah, but even F# doesn't do this sort of inference AFAIK, and they are succinct-crazy.

...our modern IDEs make it easy...

Wouldn't it be nice to see code on GitHub or StackOverflow and understand it without copy-pasting to IDE?

...My take on it is that it would be a useful feature and not more harmful than var - if used responsibly it would improve developer productivity...

The original proposal is not bad.

@paulomorgado
Copy link

@dsaf,

No need to be patronizing. I use var all the time, it does not have the problem I am talking about.

I had no intention of being patronizing!

@dsaf
Copy link

dsaf commented Aug 13, 2015

@paulomorgado Oh, ok :). Yeah, I have seen people on both sides of var camp.

@HaloFour
Copy link

Believe it or not, many developers like to read/write short code, even if at times it may seem somewhat ambiguous.

They may like to write it. They pretend they like to read it. There is a very fine line between terse and succinct and it's very easy to cross, especially when you aren't yet at the point where you are six months or more down the road and you have to maintain that code. Or someone else has to maintain that code. A program is read significantly more often than it will be written, the experience should be optimized for that.

The programming community has been through this a few times already over the decades. For a short time programming languages became obsessed with shorthand, to the point that any keyword and identifier could be referenced with as few characters as required to prevent ambiguity. It leads to N S,N,T,I,K,Q S I="K",S="11",K="l1",Q="R",T="K" being legal code. Or this little pearl.

At the end of the day, our modern IDEs make it easy to clarify any confusion by simply moving the mouse over the keyword.

Those same tools also eliminate the need to have to manually type out that class name. If you have a fully qualified and creatable type on the left side of an assignment, Intellisense defaults to that fully qualified and creatable type on the right side. All you have to hit is tab.

If you have a developer writing production code like M(new()), i can guarantee you that this will be only one of the many stylistic mistakes he/she will make :-)

The language shouldn't be walking them into making those stylistic mistakes. New developers should accidentally gravitate towards the pit of success and away from the pit of failure driven by the structure and grammar of the programming language.

And for the record, I love var and make use of it frequently. I also write a lot of Java where a lot of these same arguments are frequently made against even basic levels of inference and I find their stubbornness obnoxious (and yes, I'm well aware that I come off the same way here 😄).

@paulomorgado
Copy link

I think that written code plays a role of social interaction between the humans that work with it.

But some people are bla-bla-bla, others are just huh.

@dsaf
Copy link

dsaf commented Aug 14, 2015

Another way this could be used:

public Contact CreateContact(string name, string address)
{
    return new
           {
               Name = name,
               Address = address
           };
}

public object CreateAnonymousContact(string name, string address)
{
    return new
           {
               Name = name,
               Address = address
           };
}

At least you see what is the exact return type from the method signature, no need to guess.

@e-master e-master reopened this Aug 14, 2015
@TyreeJackson
Copy link

@dsaf
Should

public object CreateAnonymousContact(string name, string address)

be

public dynamic CreateAnonymousContact(string name, string address)

in your second example of that last post?

@e-master
Copy link
Author

Indeed, there are many places where it would be useful.
Another good one is with constructors that accept a single delegate as a parameter, e.g.:

// instead of writing
_importCustomerDataCommand = new DelegateCommand(ImportCustomerData);
// you would write
_importCustomerDataCommand = new (ImportCustomerData);

or

// instead of writing
Task loader = new Task(() => LoadSomething(someClosure));
// you would write
Task loader = new (() => LoadSomething(someClosure));

@TyreeJackson
Copy link

@e-master
If a constructor only accepts a single argument, couldn't the constructor be treated as an implicit operator? To borrow from your example:

// instead of writing
_importCustomerDataCommand = new DelegateCommand(ImportCustomerData);
// you would write
_importCustomerDataCommand = new (ImportCustomerData);
// or implicitly
_importCustomerDataCommand = ImportCustomerData;

Slippery slopes and all that.

@e-master
Copy link
Author

That same thought occurred to me too, but I don't think that treating it like an implicit operator would be a good idea. I think it would not be intuitive that it's a constructor invocation, and that's only a parameter of the constructor.

I would rather have someone define explicitly an implicit operator (pun intended) if it's really needed.

@TyreeJackson
Copy link

@e-master
Don't get me wrong, I wasn't advocating for it, just pointing out that it was the next level of implicitness (implicit constructor execution) after the implicit constructor selection with explicit execution. :-)

@e-master
Copy link
Author

yeah, slippery slope... :)

@dsaf
Copy link

dsaf commented Aug 14, 2015

@TyreeJackson anonymous objects can be implicitly cast to both object and dynamic so it doesn't matter.

@TyreeJackson
Copy link

@dsaf
Sure. I was only referring to expressing intent. I apologize, I should have made that clear. Typically, I've seen dynamic used as the return type to express that an anonymous type is likely to be returned as opposed to returning object.

@gafter
Copy link
Member

gafter commented Sep 13, 2015

Dup of #35.

@gafter gafter closed this as completed Sep 13, 2015
@gafter gafter added the Resolution-Duplicate The described behavior is tracked in another issue label Sep 13, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Language Design Resolution-Duplicate The described behavior is tracked in another issue
Projects
None yet
Development

No branches or pull requests

9 participants