Function Parameters

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: d: =

(

if c == unsupplied then print "Where's the c: argument??"

   ...

)

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 if the parameter value is a compound value such as an 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 will still be referenced by the variable in the caller.

While in some cases you may want a function to return multiple values, it typically is 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 which is passed as a parameter, you should 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

)