Discussion on:

10
Comments

Join the conversation!

Follow via:
RSS
Email Alert
Although VB6 (and many other languages as well) support optional arguments in methods, this is really not the best solution to the programming problem.

There are typically two scenarios where programmers use optional arguments. One, a method has arguments that are used to override some particular default, and two, to overload the method to accept multiple data types for what is really a single argument.

The first case usually arises when a method has been written with a specific assumption and later a case requiring a more general solutions is discovered. Rather than adding an optional argument for the unique case, one can either refactor all of the existing calls to include the default argument value, or one can create a new method that takes the additional value as a required argument. The advantage is that future programmers are now aware that they must make a choice and the existing code provides examples of the when to choose.

The second approach is when the writer of a method tries to make life easier for the eventual users by embedding data conversion within a method. This has the perverse effect of encouraging a proliferation of data types for what is actually the same value and leads to extraneous data type conversions. It is much better to pick one data type for a value and make this the standard throughout the program. Callers can then explicitly convert the data type before calling the method. In rare instances where a program needs to support two data types, separate methods should be written, with one named to indicate that it is expected to the the primary method.

I would strongly recommend that programmers avoid the use of optional arguments. These tend to harm the clarity of the program rather than enhance it.
While what you stated makes perfect sense in an ideal world, I owuld add that we often have to perform our jobs in a highly imperfect legacy world.

What you outline is great from a "groud-up" development perspective, but to advocate to avoid at all costs ignores a lot of legacy code issues. We often don't have the luxury to revise code in that manner and more often than not we are maintaining code Functions() (nee Class Methods() - but more often standard VB Functions()) that offer us no opportunity BUT to add an optional argument to implement an enhancement or correct a bug.

Overall, good post, I agree in theory, but not in practice.
0 Votes
+ -
Sorry, gotta disagree
RobinHood70 Updated - 26th Aug 2005
I'm afraid I have to disagree with your assumptions. I think the primary use for optional arguments (at least when I program) is for when arguments really are optional!

For example, I have a relatively primitive function that creates a query for a particular database server with the correct syntax. The clauses to apply filter conditions and sort orders (i.e., "WHERE" and "ORDER BY") truly are optional, and I certainly wouldn't want to create a plethora of different function calls for them, nor would I want to force the parameter to be provided. Who wants to specify three or four different parameters when only one or two are truly relevant to the call?

The "second approach" is something I've seen done mostly in .NET, though there are a few VB6 functions like InStr() where that's done as well. Here I agree with you...for the most part.

It can be very confusing to have the same function call with parameters of different types in the same logical positions. To use InStr(), in its simple form, you pass the base string and the search string in that order. In its more complex form, you pass it the offset, base string, search string, and string comparison. It's silly to have the offset come first, when you could just as easily have placed it in the third position and left the first two parameters the same for both calls (something Microsoft clued into later when they added the InstrRev function, which has both mandatory parameters out front, as they should be).

A few more good habits to get into are to force all of your optional parameters to be typed, providing default values where appropriate, and declaring variables as either ByVal or ByRef:

????Public Declare SomeFunction (Optional ByVal lngSomeParm As Long = 0).

You can't ALWAYS declare your types specifically, as this will cause the IsMissing() function to fail. Sometimes you need to distinguish between a parameter that wasn't provided at all, and one where it was. In the above example, if the parameter could legitimately have any long value, including 0, and you need to tell the difference between when something was passed and when nothing was passed, then you can't use type declarations...you MUST declare the parameter as a Variant.

(Note: you can also not declare the parameter type at all, but I consider that a bad habit to get into.)
(Note 2: I don't remember how IsMissing() works if the parameter is an Object in VB6...you might be able to get away with that and still have IsMissing() work...can anybody verify?)

So in the end, I agree to some point: don't use optional parameters to get into what are considered "bad" programming practices...but at the same time, don't hesitate to use the features a language provides, and especially if you're not sharing your work with anybody or in a team environment, don't hesitate to say "it may be bad by your standards, but it really works well for me so that's what I'm going to do".



Sincerely,
Rob Morley
0 Votes
+ -
We may have to agree to disagree regarding this, but I will contend that writing multiple methods is preferable to a single method with many branch conditions.

In the SQL example, the caller of the method will know whether he wants to provide a Where clause or an Order By clause. By providing specific methods, this choice is explicit and the called method does not need to determine this at runtime with an if statement. Since the called method now knows that the argument is required, it can validate whether the argument is present and throw an error if it is missing. This eliminates potential errors like a necessary where clause value not getting set and the code grabbing the whole table. This also saves a lot of jumping back and forth to the method definition when reading code and counting commas when omitting arguments.

There is a growing belief in programming that elimination of control statements is a good thing, and replacing single methods containing optional arguments with multiple methods containing only required arguments is one way to accomplish this. I would also suggest that you give this approach a try in your own code. I think you will find that creating multiple explicit methods preferable to single generic methods containing many if statements.
0 Votes
+ -
In fact it was the way I was taught.
As soon as you get into the multiple argument methodology, you run the risk of ending up with code that's much harder to maintain.
Effectively it's a bolt-on approach to enhancement with no refactoring.
The procedure ends up doing several different things gets too large, and harder to debug. The user of the procedure ends up with too many choices, many of which are irrelevant to the requirement.
Not sure that optional arguments is the cause of this though. Rule one when writing structured code is the procedure or function does one thing. You might have to bodge through on occasion, but a bodge is a postponement of work not an instead of.
0 Votes
+ -
Still disagree
RobinHood70 Updated - 29th Aug 2005
Sorry, but while I can understand this method for some circumstances?as someone else posted, optional parameters certainly CAN get out of hand if you're not careful?for the most part, I don't agree with it.

First of all, how many methods do you end up creating for each possible optional parameter? If you have three optional parameters to something, you end up creating 8 possible combinations...naming, if nothing else, gets to be confusing and overwhelming to the caller. God forbid you should have 5 or 6 optional parameters! (Okay, I'll admit it's not THAT common, but still!) I can't imagine trying to have .Select, .SelectOrder, .SelectWhere, .SelectWhereOrder, .SelectSpecificFields, .SelectFieldsOrder, .SelectFieldsWhere, .SelectFieldsOrderWhere

Talk about confusing! Can you imagine if something as complex as SQL were actually all designed using that philosphy? "New & Improved SQL 2020, now with over 65,000 commands!"

Also, suppose the caller is basing their input on user input? What if the WHERE clause is provided by the user? Over and above validating the input, the caller then has to use additional programming to identify the empty clause and call a different method.

Finally, with multiple methods, what are you actually gaining? You either end up writing the same code several times in several variations, possibly introducing bugs in some instances but not in others (and worse, fixing some in some instances but forgetting to fix it in others) *OR* you write parameter validation in each procedure and then end up calling a back-end procedure that handles all of the variations anyway.

What I find works best from all perspectives is simply to design your object model conceptually. To extend the database model further, you'd create one method for SELECT statements with whatever appropriate parameters, one for DELETE statements, one for INSERT, etc. It keeps your object model simple and easy to understand without excess coding.

"Elimination of control statements"? As in, no more If...Then, Do...While, or Select...Case statements? Just how far are we planning on regressing the languages? And to what end? There's no significant benefit to that theory that I can see.

As for things that are growing beliefs, I've seen far too many "growing beliefs" over the years, and I've learned to stop paying attention to them and do what makes the most sense for the application I'm designing and the audience I'm targetting it towards.

Let's take, for example, .INI files. First, they were the way to go, used all over Windows, various programs, etc. Then, the registry was the way to go, so we all used that. Now .NET comes out with its zero-touch deployment, the registry is all-but-banished, and we're all right back to using the XML-based equivalent of?guess what??.INI files!

I'm always open to new ideas, but I'm not going to jump on the band-wagon on this one just because it's "the new thing". If there's a significant gain to be made here, I've yet to hear it.
0 Votes
+ -
The difference between the two styles is simply whether you test which sort of statement to build inside the function or outside of it. I prefer the latter simply because I'm allergic to functions that have too many functions in them.
Note this has nothing to with optional arguments except in that they are used as a vehicle to create an all things to all men routine.

Order by would be a good optional argument in my opinion as the code makes sense when it's missed out, it's when you have to fill in irrelevant parameters to stop the code from crashing, that makes your teeth itch.

Fields in a select clause I'd pass in a dynamic array so it would be ['*'] or ['[Name]','[Address]', building the select clause is then just stringing them together delimited by commas.
No optional arguments and only one routine.
Even then I'd be tempted to do two routines selectall and selectspecific just to make my code clearer to the next poor pratt who had to work on it, which to me is much more important than wearing out the cut and paste function.
0 Votes
+ -
Agreed
RobinHood70 Updated - 2nd Sep 2005
I think that's where we all agree is that we need to avoid the "All things to all people" functions.

And yes, a dynamic array is probably the most logical way of doing things in a Fields parameter.

In point of fact, I'm doing things much more simply in the current version of the function, but that's all I need at the moment. The field list is simply an optional string parameter that defaults to "*" and is otherwise just a list of fields exactly as they would appear in a query, including DISTINCT clauses or what-have-you. It's not the most well-architected function, but it serves my purposes. If I were designing it for broad release, I would certainly have done it differently, including a dynamic array for fields instead of a simple string. happy



Rob
what you need to do, it's good code. I've got that one as well the multiple field list one I use to build insert statements on the fly.
0 Votes
+ -
and very powerful, they can also be gloriously misused.
Types of paraneters to a procedure don't bother me at all. Number of does, if you've gone over three it will make me suspicious about how many operations the function performs.
Unavoidable soemtimes, what I do detest is a large number of parameters, of which only a small number have to be set including the one wich tells the procedure which parameters it should pay attention to this time round.
Keyboard Shortcuts:
Prev
Next
Toggle
Join the conversation
Formatting +
BB Codes - Note: HTML is not supported in forums
  • [b] Bold [/b]
  • [i] Italic [/i]
  • [u] Underline [/u]
  • [s] Strikethrough [/s]
  • [q] "Quote" [/q]
  • [ol][*] 1. Ordered List [/ol]
  • [ul][*] · Unordered List [/ul]
  • [pre] Preformat [/pre]
  • [quote] "Blockquote" [/quote]

Join the TechRepublic Community and join the conversation! Signing-up is free and quick, Do it now, we want to hear your opinion.