www.want-tool.org
Module Parameters
   

By Andrew J. Wozniewicz
Milwaukee, August 16, 2008

Just like procedures or functions, modules can accept parameters. The following example illustrates a module (a procedure, Test) with a parameter that is passed by-value:

//Test008

procedure Test(Msg)
  WriteLn(Msg)
end

Test("Calling Test the first time")
Test("Calling Test the second time")

The output of this script is:

Calling Test the first time
Calling Test the second time

Notice that the formal parameter Msg of the Test procedure is declared without specifying its type. In general, you do not specify the types of variables or parameters in their declarations in WANTScript.

Multiple parameters can be declared in the normal way:

procedure TestProc(A, B, C)
  WriteLn("A=",A, " B=", B, " C=", C)
end

Multiple arguments in a call to such a procedure are handled in the usual way: actual arguments are bound with formal parameters by position; thus the first argument is bound to the first formal parameter; the second argument, to the second formal parameter; etc.

There is also an option of binding arguments to formal parameters explicitly by name, in which case they can be listed in any order. Here is an example of arguments bound by name:

program ArgumentsByName //Test009

  //Normal binding, by position
  TestProc("ArgA","ArgB","ArgC")
  
  //Bind all by name
  TestProc(B := "ArgB", C:= "ArgC", A := "ArgA")
  
  //Bind some by position, some by name
  TestProc("ArgA", C := "ArgC", B := "ArgB")
  TestProc("ArgA", B := "ArgB", C := "ArgC")
  TestProc("ArgA", "ArgB", C := "ArgC")

  //Invalid: Unnamed argument follows a named one
  //TestProc("ArgA", B := "ArgB", "ArgC")

  //Illegal: Binding the same argument multiple times
  //TestProc("ArgA", C := "ArgC", B := "ArgB", A := "Arg1")

  procedure TestProc(A, B, C)
    WriteLn("A=",A, " B=", B, " C=", C)
  end

end

The rule is that all arguments bound by position must be listed first, followed by arguments bound by name. Once an argument explicitly bound by name appears in the argument list, all remaining (unbound) parameters must be bound by name. An attempt to violate this rule will result in a "too many actual arguments" compile-time error.

A formal parameter can be bound only once to an actual argument. An attempt to bind multiple times to a parameter is an error. That's why the other commented-out line in the example is illegal: it attempts to bind the same parameter A first by position, then by name.

Arguments to modules in WANTScript can be passed by value, or by reference. Unless otherwise specified, arguments in WANTScript are passed by value, i.e. a copy of the actual argument's value is made for use inside the module and any modifications to the formal parameter of the module will only have localized effect within that module.

To define an argument as being passed by reference, you must prefix the argument declaration with one of the following keywords:

  • var
  • ref
  • out
  • output.

All four of these keywords have the same effect of declaring the parameter to be passed by reference. If an argument is passed by reference, any changes to the formal parameter bound to that argument will be reflected outside the called module. This is the same behavior as var-parameters in Pascal, or reference parameters in C++.

For example:

program ParamsByReference  //Test006

  var X = 0
  
  WriteLn("X=",X);
  Increment(X,2)
  WriteLn("X=",X);
  Decrement(X,1)
  WriteLn("X=",X);
  Mult(X,2)
  WriteLn("X=",X);
  Divide(X,2)
  WriteLn("X=",X);

  procedure Increment(var P, IncStep)
    P := P + IncStep
  end

  procedure Decrement(out P, DecStep)
    P := P - DecStep
  end
  
  procedure Mult(ref P, AFactor)
    P := P * AFactor
  end

  procedure Divide(output P, ADivisor)
    P := P / ADivisor
  end

end

The output of this program is:

X=0
X=2
X=1
X=2
X=1

What happens in this case is that the variable X is bound to the formal parameter P in all of the calls, whereby its value gets modified inside the respective subroutine.

An oddity of WANTScript, perhaps, is an alternative way of declaring module parameters, reminiscent of K&R C:

//Test015
procedure Build
  input Folder
  input File
  input Description = ""

  WriteLn("Folder     : ", Folder)
  WriteLn("File       : ", File)
  WriteLn("Description: ", Description)
end

Instead of declaring them inside a pair of round parentheses, you can declare them anywhere in the statement block, prefixed with the keyword input (for parameters passed by value), or any one of: output, out, or ref, for parameters passed by reference.

The procedure can be called like a function, or with a call statement, as any other:

Build("d:\projects\delphi7\want2\","want.dpr")
call Build with
  File := "want.dpr"
  Folder := "d:\projects\delphi7\want2\"
end

Here is another example of a module (procedure GetInput) that declares its parameters in the statement block, rather than in parentheses. This time, the procedure also declares an output-parameter (a parameter passed by reference):

procedure GetInput //Test023
  input Prompt
  output Value
  
  Write(Prompt)
  Value := ReadLn
end

var S

call GetInput with
  "Please, enter some text: "
  S
end
WriteLn("You entered: '",S,"'")

Here is the output produced by this script:

Please, enter some text: WANTScript is fun!
You entered: 'WANTScript is fun!'

This, admittedly somewhat archaic, style of parameter declaration helps write more readable programs in a more declarative style, if used responsibly. Of course, this feature can easily be abused by scattering parameter declarations throughout the entire module block, interspersed with executable statements (not recommended).

-Andrew