The parameters to a function are implicitly declared as local variables at the head of the function body, and are initialized with the arguments given by the caller. The parameters have a scope that extends to the end of the function body <expr>
. They can be assigned to and hidden by nested local variables with the same name as can other local variables.
Keyword parameters can be given default values in the function definition, implicitly making them optional to the caller. If the caller does not supply one of the keyword arguments, it is initialized to the default value upon function entry. The default values are specified after the ':'
(colon).
If a keyword parameter is defined with no default value and is not supplied by the caller, it is initialized to the special value unsupplied
. You can check for this value in the body of your function and handle missing required keyword argument errors accordingly.
EXAMPLE
fn foo a b: c:"default c" = ( if b == unsupplied then format "Where's the b: argument??" else format "a:% b:% c:%" a b c ) foo "A" b:"B" --> a:A b:B c:default c foo "A" b:"B" c:"C" --> a:A b:B c:C foo "A" c:"C" --> Where's the b: argument??
For more information about keyword arguments and default values, see Positional and Keyword Arguments.
As described in Reference Assignment, MAXScript uses an assignment called reference assignment. In a function, each parameter variable contains a reference to the value passed to the function by the caller. Assigning to a parameter variable places a new reference in the parameter variable, and has no effect on the variable values in the caller (it is an entirely local action). An exception to this is when the parameter value is a compound value such as, a 3D Point, string, or array, and you assign a new value to one of the components of the compound value. In this case, the variable's reference does not change, and the changed compound value is still referenced by the variable in the caller.
While in some cases you might want a function to return multiple values, it is typically not a good practice to do this by assigning to the components of a parameter variable compound value. To manipulate a compound value passed as a parameter, a compound value needs to be created in the caller and passed to the function, which can give results as shown in this example:
SCRIPT:
fn getXYZset val = ( val.x=random -100 100 val.y=random 100 100 val.z=random val.x val.y ) ( v1=[0,0,0] v4=v1 getXYZSet v1 format "v1= %; v4= %\n" v1 v4 getXYZSet v4 format "v1= %; v4= %\n"v1 v4 )
OUTPUT:
getXYZset() -- result lines 1 to 5 v1= [-84,100,78.1224]; v4= [-84,100,78.1224] -- output line 10 v1= [10,100,18.6575]; v4= [10,100,18.6575] -- output line 12 OK -- result lines 6 to 12
Note that it appears the value for both variables v1
and v4
are set in the calls to getXYZset
, even though only one variable is being passed. The reason for this is in line 8, variable v4
is initialized to the value of v1
. What actually occurs is that in line 7, a reference to a Point3 value of [0,0,0] is created and this reference is stored in v1
. In line 8, that same reference is retrieved from v1
and assigned to v4
. Rather than storing two different values, both v1
and v4
reference the same value. When you set the components of the compound value in getXYZset
, the reference to the Point3 value is not being changed, and both variables still reference that value.
The proper way to return multiple values from a function is to have the return value of the function be an array or a structure. For example,
SCRIPT:
fn readDataFile filename = ( f=openfile filename data=#() avg=0 nVals=0 while not eof f do ( val = readvalue f append data val avg += val nVals += 1 ) close f #(data,(avg/nVals)) ) result=readDataFile "c:\\datafiles\\run1.dat" data=result[1] avg=result[2]
Normally, if you are writing a function that is operating on a compound value that is passed as a parameter, you must make a copy
of the value. This prevents the value in the caller from inadvertently being changed. For example,
SCRIPT:
fn uppercase instring = ( local upper, lower, outstring upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ" lower="abcdefghijklmnopqrstuvwxyz" outstring=copy instring -- operate on copy of instring for i=1 to outstring.count do ( j=findString lower outstring[i] if j != undefined do outstring[i]=upper[j] ) return outstring )