As stated in the title, are optional parameters, such as those used in C# helpful or are they a hindrance to application maintenance and should be avoided as they can make the code harder to understand?
-
3Disclaimer: any language feature in the wrong hands can be abused. If a language implements this in a smart way, and this language feature does not overlap too much with an existing language feature in a dull way, then they are just fine, in fact quite useful. Python has some neat param packing/unpacking and other parameter "tricks" (tricks in a good, not a Perl sense).– JobCommented Dec 1, 2010 at 2:16
-
Try writing an app in C# that interfaces to Excel without using optional parameters. That should answer your question beyond any reasonable doubt.– DunkCommented Mar 1, 2016 at 22:07
10 Answers
Optional parameters have, in my experience, been a good thing. I have never found them confusing (at least no more confusing than the actual function), since I can always get the default values and know what's being called.
One use for them is when I have to add another parameter to a function that's already in general use, or at least in the public interface. Without them, I'd have to redo the original function to call one that's got another argument, and that can get really old if I wind up adding arguments more than once.
-
1+1 And it's valuable with overloaded methods that add an argument like
new Circle(size, color, filled, ellipseProportions)
wheresize
andcolor
are required and the rest are default. Commented Nov 30, 2010 at 15:38
In general, if you need many/optional parameters often, your functions are doing too much, and should be broken up. You're likely breaking SRP (Single Responsibility Principle).
Look for parameters that can be grouped, eg (x and y, become a point).
Are these optional parameters flags with a default? If you're using flags, the function should be split up.
That's not to say you should never have optional parameters, but in general, more than one or two parameters suggest a code smell.
It could also be a clue that the function, should actually be a class, with the optional parameters changed to properties, and the required parameters part of the constructor.
-
1+1 for being careful. Any feature, no matter how good, can be abused. Commented Nov 30, 2010 at 15:39
-
3This is great advice for producing overengineered ravioli code where users of your API have to use at least 6 classes and 15 functions to make even the simplest thing happen.– dsimchaCommented Dec 1, 2010 at 1:53
-
3@dsimcha, how do you get that from what I wrote? Wow. Please explain? That would be equally bad design to having a "super function" which is what you get when you have lots of optional parameters. Read about SOLID design principles, and writing testable code. Preferably using TDD. Then come back and try and explain to me that reducing parameters in functions is a bad thing.– CaffGeekCommented Dec 1, 2010 at 3:05
-
1Testable code is nice, but so is a clean, usable API that's not excessively fine-grained or verbose and doesn't shoehorn classes into situations where a function is the proper abstraction. I believe in the single responsibility principle with responsibilities defined at a high level of abstraction. If responsibilities are defined at too low a level, individual units become oversimplified such that their interactions are overly complex.– dsimchaCommented Dec 1, 2010 at 3:20
-
1@dsimcha, you're missing the point. Individual units should remain individual units, and not be lumped together in a single function. That also doesn't mean they are all publicly accessible functions. You're API is the gateway to the code, and should be clean and concise. A function with several optional parameters is neither clean, nor concise. However, overloading a single function with logical parameters is much clearer. For example, there are functions in many APIs where, two parms are optional, but one or the other is required. What's clear about that when both are marked optional?– CaffGeekCommented Dec 1, 2010 at 6:04
Optional parameters are just fine
Typically the justification is either that a) you know you have a lot of possible arguments for your method but you don't want to overload for fear of clutering your API, or b) when you don't know all the possible arguments but you don't want to force your user to provide an array. In each case optional parameters come to the rescue in a neat and elegant way.
Here are some examples:
1. You want to avoid overloading and don't want to specify an array
Take a look at printf() from C, Perl, Java etc. It's a great example of the power of optional parameters.
For example:
printf("I want %d %s %s",1,"chocolate","biccies");
printf("I want %d banana",1);
No overloading, no arrays, simple and intuitive (once you've grasped the standard string format codes). Some IDEs will even tell you if your format string does not match your optional parameters.
2. You want to allow the use of defaults and keep them hidden from the user of the method
sendEmail("[email protected]");
The sendEmail method detects that various essential values are missing and fills them in using defined defaults (subject, body, cc, bcc etc). The API is kept clean, yet flexible.
A note on too many parameters
However, as others have stated, having too many mandatory parameters to a method indicates that you probably have something wrong with your design. This is particularly true if they share the same type since they can be switched by the developer by accident leading to strange results at runtime:
String myMethod(String x, String y, String z, String a, int b, String c, int d) {}
is an ideal candidate for the Introduce Parameter Object refactoring to create
String myMethod(ParameterObject po) {}
class ParameterObject {
// Left as public for clarity
public String x;
public String y;
... etc
}
This in turn can lead to a better design based on a Factory pattern with a provided specification as the parameter object.
-
1string formatting functions like printf are the exception to the rule, one could argue that while they use a limitless list of optional parameters, it's more like the argument is an array than it is optional parameters, despite how it is implemented.– CaffGeekCommented Nov 30, 2010 at 18:02
-
@Chad I've adjusted my answer to better differentiate between optional parameters and when they transition into a code smell (as you have mentioned in your answer).– GaryCommented Nov 30, 2010 at 19:00
-
@Gary Rowe, too many optional parameters are bad too in most cases.– CaffGeekCommented Nov 30, 2010 at 19:52
-
@Chad I agree, but most languages don't provide a way to specify a limit on the number of optional arguments so it's an all or nothing approach. You are forced to leave it to your method to enforce and obviously if your method is dealing with 500 variables then it's definitely going to need to be refactored.– GaryCommented Nov 30, 2010 at 20:00
-
@Gary Rowe, what do you mean "most languages don't provide a way to specify a limit on the number of optional arguments"? In most languages you mark them as such, or don't provide them values when calling the function, but the function header still has the parameters defined. Granted, in some languages you can add as many parameters you want after you have filled in the defined ones, but I don't think that's the kind of optional parameters we are talking about here. (aside from the string format exception)– CaffGeekCommented Nov 30, 2010 at 20:35
One of the problems with default parameters in C# ( I'm thinking void DoSomething(int x = 1) ) is they are constants. That means if you change the default you will have to recompile any consumers of that method call. While this is easy enough to do there are occasions where this is dangerous.
The problem with optional arguments is that people tend to just tuck on more and more (and more) arguments to the function instead of extracting relevant code into a new function. This is taken to the extreme in php. For instance:
bool array_multisort ( array &$arr [, mixed $arg = SORT_ASC
[, mixed $arg = SORT_REGULAR [, mixed $... ]]] )
I have initially loved this feature in python, and used it to 'extend' already used methods. And it looked nice and easy, but it bit back soon; because when I added an optional parameter, this was modifying the behavior of an existing method which the old client relied upon and in a way which was not caught by existing unit test cases. Basically doing this is breaking the Open Closed Principle; code is open for extension but closed for modification. So I believe using this feature to modify existing code is not a good idea; but okay if used from the start
I'd think it would be better to overload a function with different signatures (i.e. parameters) than use optional parameters.
-
Why? I think its more cleaner if you can combine a bunch of overloaded methods into one method using default params if all the methods have the same basic functionality Commented Dec 9, 2010 at 2:23
-
1You can think that. I'm not one to think Microsoft does everything the right way, but if you were accurate, then I'd never see overloads when using the .NET framework, just one huge function signature - like in the ol' VB6.– HardCodeCommented Dec 9, 2010 at 16:41
It depends on what your code is doing. If there are sensible defaults then you should use optional parameters but if there are no sensible defaults then adding optional parameters will make your code more complicated. In many instances optional parameters are a neat way of sidestepping nil checks and cutting out branching logic. Javascript doesn't have optional parameters but there is a way to emulate them with || (logical or) and I use it all the time when doing database related stuff because if the user doesn't provide some value then I substitute my own values with the help of || which saves me the trouble of writing a whole bunch of if then statements.
Optional parameters are basically a different way of overloading a function. So this basically comes down to: "is overloading a function bad"?
Optional parameters are a great way to make simple things simple and complicated things possible simultaneously. If there's a clear reasonable default that most users will want, at least in quick and dirty use cases, then they should not have to write boilerplate to manually specify it every single time they call your function. On the other hand, if people might have a good reason for wanting to change it, then it needs to be exposed.
Using a class is IMHO a terrible solution, as it's verbose, inefficient and inconsistent with the typical mental model of what a class does. A function is the perfect abstraction for a verb, i.e. doing something and returning. A class is the right abstraction for a noun, i.e. something that has state and can be manipulated in several ways. If the former should be the API user's mental model, then don't make it a class.