.NET Forum / .NET Framework / CLR / February 2005
Proposal: Default Parameters/Named Parameters
|
|
Thread rating:  |
cody - 02 Feb 2005 18:40 GMT Why doesn't C# allow default parameters for methods? An argument against I hear often is that the default parameters would have to be hardbaken into the assembly, but why? The Jit can take care of this, if the code is jitted the "push xyz" instructions of the actual default values can be inserted.
To make things simpler and better readable I'd make all default parameters named parameters so that you can decide for yourself why one to pass and which not, rather than relying on massively overlaoded methods which hopefully provide the best overload for you, for example the Image.DrawImage method has 20 overloads.
I propose a syntax like the following:
public void Open(string path, AccessMode mode = AccessMode.Read, int bufferSize=1024) { // ... }
As you can see, path is a regular parameter which cannot be omitted, whereas Mode and BufferSize provide default values an can be omitted when calling the method. Named parameters can only be declare behind all regular parameters and if you have params parameters (variable parameterlist) is must be declared at the end of the parameterlist. Although you can omit the named parameters if you pass them they should appear in the same order as they were declared for better readability.
You could call the example method like the following:
Open("text.txt", @mode=AccessMode.Write, @bufferSize=512); Open("text.txt", @bufferSize=512); Open("text.txt", @mode=AccessMode.Write); Open("text.txt");
Note that an @ sign has to appear before all named parameter so that you have no naming conflicts with other variables in the callers context.
Additionally there can not be more that one method with the same name and the same regular parameters to avoid ambigiuty, so:
Foo(int i, string a=""); Foo(int i, double f=1.0f);
Would not be allowed because the call Foo(100) could not be resolved.
What do you think about that? Would it even be possible to do that in the CLR or would there have be so huge changes that it can't be done in the future?
Bruce Wood - 02 Feb 2005 19:22 GMT Anders Hejlsberg touched on this during his (very interesting) whiteboard talk:
http://msdn.microsoft.com/msdntv/episode.aspx?xml=episodes/en/20040624csharpah/m anifest.xml
Basically, there are several ways to implement default arguments.
The first is to have the compiler build the defaults into the method call on the caller's side. Essentially the called method would receive all of its parameter arguments every time and not have to worry about missing arguments, because the caller would take care of filling in the blank. Hejlsberg's objection to this is that it would involve compiling the defaults into the caller, which would break all of your callers if you ever changed the defaults.
However, you're suggesting doing it during the JIT phase, which would remove that objection, but require changes to the IL. An interesting idea.
The other possibility is to have the called method handle defaulting, but this would come with a mondo speed penalty, as I think Hejlsberg points out.
Personally, the only place I've found that really could use optional parameters is when writing constructors. Most other methods don't experience the kind of massive overloading that constructors do, and the only part of writing constructor overloads that I hate is having to copy (and maintain) the documentation on every overload.
Someone also mentions this to Hejlsberg as a compromise: allowing sharing of XML documentation between overloaded methods / constructors. That would make me happy enough, without changing the IL, the JITter, and the definition of what a C# method signature looks like.
cody - 03 Feb 2005 00:43 GMT > Personally, the only place I've found that really could use optional > parameters is when writing constructors. Most other methods don't > experience the kind of massive overloading that constructors do, and > the only part of writing constructor overloads that I hate is having to > copy (and maintain) the documentation on every overload. There are a lot of methods that take a lot for than 5 arguments and have multiple overloads like the framework class Image which method DrawImage has 20 overloads!
I think this heavy overlading makes the code less readable and unnessaccary bloated. So if you have just 5 overloads you have to write at least 5*5 lines of code and this is without documentation. You often do not see which overloaded method calls which and you sometimes end up with an endless recursion. You have also take care that the parameters ar in the same order in each method to provide good readability. Additionally if you do not do it clean and put additional code in the overadloaded methods beside the call of the "main worker method" end up with very messy code like that:
Foo(double d, string s, int i, bool b) { // dostuff }
Foo(double d, string s, int i) { Foo(d, s, 0, false); // do some stuff here }
Foo() { Foo(0, "", 0, false); // do some stuff here }
Foo(double d) { Foo(0, "", 0, false); // do some stuff here }
Foo(int i) { Foo(0, "", i, false); // do some stuff here }
Foo(double d, string s) { Foo(d, s, i, false); // do some stuff here }
At the end, you have a huge piece a crap in you texteditor where you just would have needed JUST ONE SIMPLE METHOD.
Bruce Wood - 03 Feb 2005 07:04 GMT Do I need to point out that if each overload has some extra "do some stuff here" code that isn't in the "master method" then you couldn't code it any better using default arguments? :)
Really, for my money the only annoying thing about having to use overloads is copying the documentation over and over again. Fix that problem and I would be quite happy with the status quo.
"Rick Byers [MSFT]" - 07 Feb 2005 21:12 GMT Note that emitting default values at JIT time wouldn't cover the important case where the caller is an ngen'd image. It's not clear to me off hand how you could support that scenario in an efficient manor.
I'd personally love to see something like this, but only if it could be efficiently implemented without sacrificing the simplicity and elegance of C#. The complexity of overload resolution in C++ (and resulting costs) was probably a driving factor in the C# design. I know Anders and his team have spent some effort trying to come up with an acceptable solution here (and they would have asked for CLR support if they thought it would help).
Regardless, feel free to add your comments and vote to this topic in the MSDN product feedback center: http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=8 2bdeff1-0588-4c9d-9172-7c4f1eab0f8c
We take that feedback very seriously, and try to allocate our resources in proportion to the demand from the community.
Rick
-------- This posting is provided "AS IS" with no warranties, and confers no rights. --------------------
> From: "Bruce Wood" <brucewood@canada.com> > Newsgroups: microsoft.public.dotnet.framework.clr,microsoft.public.dotnet.languages.csha rp
> Subject: Re: Proposal: Default Parameters/Named Parameters > Date: 2 Feb 2005 11:22:29 -0800 > > Anders Hejlsberg touched on this during his (very interesting) > whiteboard talk: http://msdn.microsoft.com/msdntv/episode.aspx?xml=episodes/en/20040624csharp ah/manifest.xml
> Basically, there are several ways to implement default arguments. > [quoted text clipped - 24 lines] > That would make me happy enough, without changing the IL, the JITter, > and the definition of what a C# method signature looks like. cody - 07 Feb 2005 22:40 GMT Even if using an NGened image, it would certainly be possible to "rejit" some portions of the code.
But if you ask me NGen as a whole goes completely against the spirit of a virtual machine and defeats all of its advantages like dynamically optimizing and creating code and so on. Couldn't we simply say that from the version on where named parametern are supported NGen is no longer supported?
NGen serves no other purpose than having precompiled code, you could have the same effect if you would enable the CLR to cache every assembly which is in the GAC as native image. And only if a assembly changes (which means there could be a new default value of a named parameter) all depending assemblies have to be re-precompiled by the CLR on demand.
> Note that emitting default values at JIT time wouldn't cover the important > case where the caller is an ngen'd image. It's not clear to me off hand [quoted text clipped - 63 lines] >> That would make me happy enough, without changing the IL, the JITter, >> and the definition of what a C# method signature looks like. cody - 07 Feb 2005 23:42 GMT > Note that emitting default values at JIT time wouldn't cover the important > case where the caller is an ngen'd image. It's not clear to me off hand > how you could support that scenario in an efficient manor. Maybe I understood you wrong. In case of an NGened image we simple pass *all* of the parameters to the method in the order they are declared in it. At the end there is no performance penalty because when programming with the main method pattern to fake optional parameters using heavy overloading we also have to call the main method with *all* parameters.
What would happen if I change the default value? In that case the method signature has changed in which case the NGened images are incompatible and have to be recompiled anyway.
Another great idea is that we use the same syntax I proposed, but we let the c# compiler emit the various overloaded methods so they do not clutter our sourcecode anymore but instead are located in the assembly. This way we stay very compatible because we do not have to modify the CLR but only the c# compiler and we dealt gracefully with modifying default values because they are stored in the assembly. But this approach has its drawbacks - we can only omit the parameters from the end of the parameter list and cannot simply leave some arguments out. But I think this would be very enough for the most common uses.
> I'd personally love to see something like this, but only if it could be > efficiently implemented without sacrificing the simplicity and elegance of [quoted text clipped - 59 lines] >> That would make me happy enough, without changing the IL, the JITter, >> and the definition of what a C# method signature looks like. "Rick Byers [MSFT]" - 08 Feb 2005 20:06 GMT Of course, you're right - the requirement to re ngen an image when any of its referenced assemblies changes means the burned-in defaults would be updated. I don't know what I was thinking - thanks for keeping me honest <grin>. Note, by the way, that in his whiteboard talk Anders indicated that the burn-in problem may not be that important.
Having the compiler emit a series of overloads also sounds like a decent option (although it does still increase the complexity and potential for error in overload resolution). However, during his whiteboard talk, Anders' mentioned the possibility of object initialization syntax that may be an even better option. Basically, instead of writing default arguments like this:
public MyClass( int arg1=0, string arg2="foo", object arg3=null )
you would use properties like this:
public MyClass() { Arg1=0; Arg2="foo"; Arg3=null; } public int Arg1 { get {...} set {...} } public string Arg2 { get { ... } set {...} } public object Arg3 { get {...} set {...} }
And then you could easy create an instance with a statement like new MyClass{ Arg1=4, Arg3=o }
If you didn't want to expose your constructor parameters as properties (i.e. you didn't want to let people change them after construction), you could just wrap them all up in a struct and use the object construction syntax to create a set of values that you pass to the constructor. This would also be usefull for other (non-constructor) methods with long argument lists.
I like this a lot (especially since it's avoids the overload resolution complexity in languages like C++, and doesn't require any CLR support). There is something about optionally named arguments I've always found appealing, and Anders' suggestion has that same appeal. Hopefully we'll see something like this in C# 3. Of course, I have no idea how likely this would be. If you like it, you should vote on it in the product feedback center (http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid= 6efe5713-405f-4808-9449-9caa0f116d6f).
Rick
-------- This posting is provided "AS IS" with no warranties, and confers no rights. --------------------
> From: "cody" <deutronium@gmx.de> > Subject: Re: Proposal: Default Parameters/Named Parameters [quoted text clipped - 34 lines] > > Regardless, feel free to add your comments and vote to this topic in the > > MSDN product feedback center: http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=8
> > 2bdeff1-0588-4c9d-9172-7c4f1eab0f8c > > [quoted text clipped - 9 lines] > >> From: "Bruce Wood" <brucewood@canada.com> > >> Newsgroups: microsoft.public.dotnet.framework.clr,microsoft.public.dotnet.languages.csha
> > rp > >> Subject: Re: Proposal: Default Parameters/Named Parameters > >> Date: 2 Feb 2005 11:22:29 -0800 > >> > >> Anders Hejlsberg touched on this during his (very interesting) > >> whiteboard talk: http://msdn.microsoft.com/msdntv/episode.aspx?xml=episodes/en/20040624csharp
> > ah/manifest.xml > >> [quoted text clipped - 26 lines] > >> That would make me happy enough, without changing the IL, the JITter, > >> and the definition of what a C# method signature looks like. cody - 08 Feb 2005 21:44 GMT > However, during his whiteboard talk, > Anders' mentioned the possibility of object initialization syntax that may [quoted text clipped - 17 lines] > And then you could easy create an instance with a statement like > new MyClass{ Arg1=4, Arg3=o } I do not like that proposal. I do not see any benefit of using
MyClass obj = new MyClass { Arg1=4, Arg2=o Arg3=o }
over
MyClass obj = new MyClass(); obj.Arg1=4; obj.Arg1=o; obj.Arg3=o;
I find the first harder to read and it suggests that you cannot alter the values afterwards, additionally it doesn't look consistent to the rest of c#, it has something from the "with" statement which also does not fit into the language which is also anders' opinion.
And it can only be used with ctors which introduces additionally inconsistency, it is not only that I do not like it, I hate it!
<endofcomments>
> If you didn't want to expose your constructor parameters as properties > (i.e. you didn't want to let people change them after construction), you [quoted text clipped - 134 lines] >> >> That would make me happy enough, without changing the IL, the JITter, >> >> and the definition of what a C# method signature looks like. "Rick Byers [MSFT]" - 14 Feb 2005 18:43 GMT You make some good points, and I agree the benefit isn't clear but I still think the proposal has some merrit. I don't envy the C# team's job of trying to satisfy as many people as possible without upsetting too many <grin> when it's such a religious issue. The art of language design is sufficiently subjective and debatable, that at some point you just need an expert (like Anders) to make a judgement call (which is precisely what has been done to date with default parameters).
Regardless, feel free to give the C# team your feedback (either in the product feedback center, the C# language discussion group[1], or the languages.csharp newsgroup). Debating this issue on the CLR group probably isn't going to get us anywhere since it's utlimately a language issue, even if the CLR ends up providing support for the implementation.
Rick
[1] http://www.gotdotnet.com/Community/MessageBoard/MessageBoard.aspx?ID=5627
-------- This posting is provided "AS IS" with no warranties, and confers no rights. --------------------
> From: "cody" <deutronium@gmx.de> > Subject: Re: Proposal: Default Parameters/Named Parameters [quoted text clipped - 67 lines] > > would be. If you like it, you should vote on it in the product feedback > > center (http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=
> > 6efe5713-405f-4808-9449-9caa0f116d6f). > > [quoted text clipped - 58 lines] > >> > the > >> > MSDN product feedback center: http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=8
> >> > 2bdeff1-0588-4c9d-9172-7c4f1eab0f8c > >> > [quoted text clipped - 10 lines] > >> >> From: "Bruce Wood" <brucewood@canada.com> > >> >> Newsgroups: microsoft.public.dotnet.framework.clr,microsoft.public.dotnet.languages.csha
> >> > rp > >> >> Subject: Re: Proposal: Default Parameters/Named Parameters > >> >> Date: 2 Feb 2005 11:22:29 -0800 > >> >> > >> >> Anders Hejlsberg touched on this during his (very interesting) > >> >> whiteboard talk: http://msdn.microsoft.com/msdntv/episode.aspx?xml=episodes/en/20040624csharp
> >> > ah/manifest.xml > >> >> [quoted text clipped - 30 lines] > >> >> That would make me happy enough, without changing the IL, the JITter, > >> >> and the definition of what a C# method signature looks like. cody - 15 Feb 2005 08:43 GMT > You make some good points, and I agree the benefit isn't clear but I still > think the proposal has some merrit. The Property calling syntax in ctors enables you to initialize an object and call properties of it in array initializers:
object[] array = { new MyClass{Prop1=val1,Prop2=val2} };
But when would somebody actually need that?
> I don't envy the C# team's job of > trying to satisfy as many people as possible without upsetting too many [quoted text clipped - 90 lines] > > > would be. If you like it, you should vote on it in the product feedback > > > center (http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=
> > > 6efe5713-405f-4808-9449-9caa0f116d6f). > > > [quoted text clipped - 67 lines] > > >> > the > > >> > MSDN product feedback center: http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=8
> > >> > 2bdeff1-0588-4c9d-9172-7c4f1eab0f8c > > >> > [quoted text clipped - 11 lines] > > >> >> From: "Bruce Wood" <brucewood@canada.com> > > >> >> Newsgroups: microsoft.public.dotnet.framework.clr,microsoft.public.dotnet.languages.csha
> > >> > rp > > >> >> Subject: Re: Proposal: Default Parameters/Named Parameters > > >> >> Date: 2 Feb 2005 11:22:29 -0800 > > >> >> > > >> >> Anders Hejlsberg touched on this during his (very interesting) > > >> >> whiteboard talk: http://msdn.microsoft.com/msdntv/episode.aspx?xml=episodes/en/20040624csharp
> > >> > ah/manifest.xml > > >> >> [quoted text clipped - 37 lines] > JITter, > > >> >> and the definition of what a C# method signature looks like. Carl Shapiro - 13 Feb 2005 08:49 GMT > Note that emitting default values at JIT time wouldn't cover the important > case where the caller is an ngen'd image. It's not clear to me off hand > how you could support that scenario in an efficient manor. Efficient compilation of function calls with optional named parameters is a problem that has been studied by Lisp implementors. One approach used by aggressively-optimizing Common Lisp compilers that may be useful in this situation is to provide multiple external entry points for functions which take optional named parameters. One entry point would be for the fast case: a function call with all parameters supplied. Entering a function through the fast entry point should be no more expensive than calling a method with only mandatory positional arguments. Another entry point, the default entry point, would be for function calls where unsupplied arguments would be filled in. (After all values are moved into place the function would fall through or jump to the fast entry point.) In this case, the call should be no more expensive than a function which tests and assigns default values to unsupplied optional parameters. Other entry points could be made available for various combinations of supplied and unsupplied parameters, although this could easily become unmanageable. If space is of concern, the entire defaulting operation could be performed in a small out-of-line subroutine.
Actually, with the params keyword, you can implement named optional parameters in a simpleminded way: pass pairs of keywords and values in the params vector.
func(param1, param2, "keyword1", value1, "keyword2", value2)
I am surprised nobody has suggested something like this. Granted, the syntax is just awful; it's not immediately clear what the programmer is trying to say. On the other hand, it is representative of what could be happening under the hood. If we could cheat on the syntax for argument lists, and rather than using random strings, we had a way to ask for self-evaluating constant strings, this expression could be made less of an eye-sore
func(param1, param2, keyword1: value1, keyword2: value2)
A small out-of-line subroutine could be invoked to scan the params vector and move keyword-values into predetermined local variables.
Imagine if the compiler could do that for you!
"Rick Byers [MSFT]" - 14 Feb 2005 18:49 GMT Thanks for your input Carl. I agree that using multiple entry points is probably the best way to prevent burn-in without getting any support from the CLR.
For your params-based named parameters proposals, keep in mind that most C# users may not be willing to give up strong typing for a relatively minor cosmetic feature like named/default parameters (which makes it significantly different from the Lisp environment where you've got a lot more freedom in this respect). Of course, named parameters could be added to the language in a simple strongly-typed way if there was sufficient demand.
Rick
-------- This posting is provided "AS IS" with no warranties, and confers no rights. --------------------
> From: Carl Shapiro <cshapiro+spam@panix.com> > Newsgroups: microsoft.public.dotnet.framework.clr [quoted text clipped - 44 lines] > > Imagine if the compiler could do that for you! Bob Powell [MVP] - 02 Feb 2005 20:37 GMT Default parameters are not needed when overloading can do the job for you.
The parameter lists scan from left to right anyway so all you have to do is overload the function once for each extra parameter in the list.
 Signature Bob Powell [MVP] Visual C#, System.Drawing
Find great Windows Forms articles in Windows Forms Tips and Tricks http://www.bobpowell.net/tipstricks.htm
Answer those GDI+ questions with the GDI+ FAQ http://www.bobpowell.net/faqmain.htm
All new articles provide code in C# and VB.NET. Subscribe to the RSS feeds provided and never miss a new article.
> Why doesn't C# allow default parameters for methods? > An argument against I hear often is that the default parameters would have [quoted text clipped - 46 lines] > CLR or would there have be so huge changes that it can't be done in the > future? Bruce Wood - 02 Feb 2005 20:50 GMT There is one situation in which _named_ parameters, as outlined by cody, would be helpful, and that is when you have what really ought to be two different overloads that take the same parameter types, something like
public Page (int width, int height)
public Page (int width)
now, if you want another constructor overload for Page that creates a Page with a default width and a given height, you're stuck.
However, I'm fairly certain that it's not worth reworking the C# language and the IL in order to handle this one, rare case.
Bob Powell [MVP] - 02 Feb 2005 21:08 GMT It strikes me that this can be done with attributes. I'll have to think about it.
 Signature Bob Powell [MVP] Visual C#, System.Drawing
Find great Windows Forms articles in Windows Forms Tips and Tricks http://www.bobpowell.net/tipstricks.htm
Answer those GDI+ questions with the GDI+ FAQ http://www.bobpowell.net/faqmain.htm
All new articles provide code in C# and VB.NET. Subscribe to the RSS feeds provided and never miss a new article.
> There is one situation in which _named_ parameters, as outlined by > cody, would be helpful, and that is when you have what really ought to [quoted text clipped - 10 lines] > However, I'm fairly certain that it's not worth reworking the C# > language and the IL in order to handle this one, rare case. cody - 03 Feb 2005 00:28 GMT Please tell me if you should have a new idea!
> It strikes me that this can be done with attributes. I'll have to think > about it. [quoted text clipped - 13 lines] >> However, I'm fairly certain that it's not worth reworking the C# >> language and the IL in order to handle this one, rare case. cody - 14 Feb 2005 16:01 GMT > It strikes me that this can be done with attributes. I'll have to think > about it. Iam just curious if you've got new ideas about this topic :)
> Find great Windows Forms articles in Windows Forms Tips and Tricks > http://www.bobpowell.net/tipstricks.htm [quoted text clipped - 19 lines] > > However, I'm fairly certain that it's not worth reworking the C# > > language and the IL in order to handle this one, rare case.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|