Block-Expressions

Block-expressions are the basic constructors for structured code. They allow you to group a sequence of expressions and evaluate them in sequence as though they were a single expression.

The syntax for <block_expr> is:

( <expr> { (; | <eol>) <expr> } )

That is, a parenthesized sequence of expressions with each <expr> separated by either a line break or a "; " semicolon.

MAXScript also allows empty block-expressions, (). This is useful when incrementally building code in order to place an empty expression in a path to be filled in later. When evaluated, empty expressions yield the value undefined.

Examples:

(

d = centre.x^2 - (p.x^2 + p.y^2)

newz = if d > 0 then sqrt d else p.z

print newz

)

if x < y then (print x; print y; u += 10; print u)

You can use a mixture of line breaks or semicolons:

(

print x; print y

u += 10

print u; print z

)

Because a block-expression is an <operand>, you can insert a block-expression anywhere you can put an <operand>. This is unlike most languages which limit where you can put blocks of code to only a few places. Further, because all constructs are expressions in MAXScript, a block-expression yields a value defined to be the last <expr> in the block. This allows you to use a nested sequence of expressions to compute an operand for some operation:

$box.pos.z =

(

d = x^2 - y^2

if d > 0 then sqrt d else z

)

Here, the result of the block-expression is the result of the final if expression, which is then assigned to $box.pos.z.

Because the item in parentheses can be any <expr>, you can turn any construct in MAXScript into an operand by putting it in parentheses. This allows you to write the following example, in which the operand to be indexed is the conditional result of an if expression:

(if a > b then c else d)[n + 1]

As described in Scope of Variables, top-level open parentheses in a script file or in the Listener create a new variable scope. Any block-expressions with the top-level block-expression do not create a new variable scope, even if the variable is explicitly declared as local in the inner block-expression. A variable’s scope extends into any block-expressions within the variable’s scope. If you declare a variable as local in a scope, the newly declared local variable hides any outer variables with the same name. Any reference to that variable name later in the local variable's scope refers to the new local variable. At the end of the local variable's scope, the next outer variable becomes visible again. This is shown in the following script:

Script:

a=1

(

local a=2

(

local a=3

)

print a

)

a

Output:

1 -- result of line 1

3 -- output of line 7

3 -- result of block-expression lines 2 to 8

1 -- result of line 9

Any variable names used in a block-expression which have not been created at a higher scope level are implicitly declared as local in the present scope. This can result in unexpected execution results for scripts that are not set up correctly. For example, consider the following script:

(b=bend();addmodifier Objs b) -- create bend modifier and apply to objects

b.angle=10

The first time you execute this script, the following error message is generated:

-- Unknown property: "angle" in undefined

If you execute the script again, it works properly. The reason is there are actually two variables with the name b - one is local to the block-expression and contains the bend modifier value, and the other is global and has the value undefined. During the second execution, global b exists, so the block-expression does not implicitly declare a new variable b, rather it uses the global variable b.

When writing scripts, it is also a good programming practice to explicitly declare as local all variables unless you really want them to be global variables. There are several reasons for this practice:

(if false do box=10;box)