First of all, if a function has a long list of arguments, say, more than 5 or 6 arguments, then it is complex. It is likely to be doing too many things. As a rule, a function should have just one responsibility. You should split such complex functions up into 2 or more separate functions.
To avoid ambiguity, use the name of the arguments when you call the function. For example, suppose that myFunc has arguments arg1, arg2,..., arg6, all of which are optional. Then you could call it as follows: myFunc(arg3="Journal",arg5="2014").
The nature of this project requires the long lists of arguments, and I do use names with optional arguments. The issue I'm having is when I invoke a function expecting "status_code" as an argument with an argument of "status" instead. The function executes with status_code at its default value and status just sitting in the arguments scope unused. This is never intentional, but happens on occasion. I would like coldfusion to throw an error any time there is something in the arguments scope that is not an expected argument.
Please bear with me: I still don't get it. What do you mean by, "when I invoke a function expecting "status_code" as an argument with an argument of "status" instead. The function executes with status_code at its default value and status just sitting in the arguments scope unused" ?
Could you just paste a little code here to illustrate? Thanks.
I think I get it now. The argument name is status_code, but what gets into the function is arguments.status instead of arguments.status_code. Right?
If so, you should check where the function is called with the argument status_code. There might be a space between status and _code. In any case, at the point where the function is called, retype the name status_code, just to be sure.
I would like coldfusion to throw an error any time there is something in the arguments scope that is not an expected argument.
Use code similar to that in bold.
<!--- List arguments in alphabetical order to enable comparison --->
<cfif listSort(StructKeyList(arguments),"textnocase","asc") is not "arg,myArg,myOtherArg">
<cfthrow message="An unexpected argument was passed to the function">
Your understanding was correct. I was hoping to find a coldfusion setting to enable some sort of "strict mode" on function calls, but using this code did the job and only required a paste into each function. Note: works only on CF 9+
<!--- Include this invoke in any function to check the arguments --->
<cfinvoke component="validation" method="verify_arguments">
<cfinvokeargument name="accepted_arguments" value="#ARGUMENTS#">
<cfinvokeargument name="declared_arguments" value="#GetMetaData(Evaluate(GetFunctionCalledName())).parameters#">
<!--- Function it calls for reference --->
<cffunction name="verify_arguments" access="public" output="yes">
<cfargument name="accepted_arguments" required="yes">
<cfargument name="declared_arguments" required="yes">
<cfif ArrayLen(declared_arguments) IS NOT ArrayLen(accepted_arguments)>
<h2 class="warning">Function has accepted more arguments than were declared.</h2>
The issue arises because Coldfusion is weakly typed. As such, it cannot support method overloading. So I understand what you are aiming at. You could nevertheless improve the design.
At the moment, you give responsibility for checking the arguments to the function itself. That design reduces cohesion. Ideally functions should be defined such as to perform one service. Making them to validate arguments, on top of the task they each have to perform, introduces unnecessary complexity, hence reduced cohesion.
The 'Design By Contract' (DbC) paradigm suggests a solution. The validation of arguments - as you have done - is an example of a precondition in DbC. A precondition is carried out as follows:
1) by the caller of a function;
2) before the function runs.
Delegating the task to the caller is inevitable. In software design, you delegate tasks and responsibilities ideally to the party that has the most information necessary to perform them. (This is sometimes called the G.R.A.S.P. pattern). In this case, that party is the caller of each function. For the caller is the specialist who, better than anyone else, is aware of the parameters that are used to call a function.
This improved design leaves your above validation code basically unchanged. Above all, it has the tremendous advantage of leaving your functions intact. Imagine how much refactoring, debugging and hair-tearing this would save you if you had, say, 2000 functions.