Notifications
Clear all

[Closed] fileIn function scope

You are misunderstanding something.
*First of all, not every pair of parentheses opens a new scope. So both your “local” variables are in the same scope. Please read the sub-topic “Implicit Variable Declaration” in “Scope of Variables”. Only top level parentheses and bodies of functions, for loops, utility, rollout, rcmenu, macroScript and tool definitions, bodies of event handlers and when constructs create a new scope.

*Second, when you don’t declare a variable in the local scope, it is assumed to be local only if there is no other variable in any parent scopes, including the global scope.

*Third (and this is the surprise), when a global variable is found and you declare a variable implicitly in a lower scope, it looks like a local variable is created in the scope that simply points at the same memory address as the global one, but it is still technically a local variable. (I have to check with the developers of MAXScript since this is not documented anywhere AFAIK).

So your code does this:


   global R = "GlbR" --declare and define a global variable
   fn checkR = --opens a new local scope below the global scope
   (
   	R = "fnR" --implicit declaration, goes up looking for the same name, 
   	--finds R in global scope, "local" R's pointer set at the global's memory 
   	--so global R's memory is overwritten with the value "fnR"
   	AssertNotEqual R ::R --this shows correctly that local and global R share memory
   	(--does NOT create a new scope!
   		local R = "LocR" --this is in the same scope as the R above, so it overwrites both
   		--the local R and the global R since they point at the same memory already.
   		AssertNotEqual R ::R --it shows correctly the local R and global R share memory
   	)--does nothing
   )--closes the only local scope
   checkR()

So adding explicit local to the first declaration fixes this, and the second local R just overwrites the same variable since both are in the same scope:

global R = "GlbR"
   fn checkR = 
   (
   	local R = "fnR"
   	AssertNotEqual R ::R
   	(
   		local R = "LocR"
   		AssertNotEqual R ::R
   	)
   )
   checkR()

One more reason to always declare local variables explicitly!

Thanks for the clarification Bobo.

I admit I worked up those examples by wrapping code that started as top level blocks in the listener inside of functions then culling them down to just what I believed I needed. When I really think about it, it makes sense not to require a new scope for implicit variables in an interpreted language. Seems that every day I need to remind myself “this is maxscript, not perl, not c++, not c#, etc)

Given your excellent feedback, here is a clearer (at least to me) example of what can happen, and why we should always use strict scoping:

global A = "GlbA"
global B = "GlbB"

fn checkAB = 
(
  -- implicit A hides global
	A = "ImpA"
	AssertNotEqual A ::A
	local A = "LocA"
	AssertNotEqual A ::A

 -- local B does not hide global	
	local B = "LocB1"
	AssertNotEqual B ::B
	B = "LocB2"
	AssertNotEqual B ::B
)
checkAB()

output:

ImpA != ImpA is false
LocA != LocA is false
LocB1 != GlbB is true
LocB2 != GlbB is true

All these years and I never knew about a :: in maxscript ! We never stop learning from you Bobo, thanks

Page 2 / 2