Notifications
Clear all

[Closed] Using "&" to force reference

I was having trouble with a Fn overriding an array.
A joyous coworker showed me that I’d have to force reference on the variable coming into the FN.I looked through max script help for this and couldn’t find any information, probably just missed it.

I’m still trying to wrap my head around it and would like to know why i actually have to brute force this.
here is an example:


 (
 local aa = #(1,2,3,)
 
 fn OverRideArray &TheArray =
 (
 local TheNewArray  = #("a")
 TheArray = #()
 TheArray = TheNewArray
 )
 OverRideArray &aa
 
 )
 

Is this because when i say TheArray = #() inside the Fn max is creating a local varible inside the Fn?

Cheers

10 Replies
1 Reply
 eek
(@eek)
Joined: 10 months ago

Posts: 0

From my understanding its a reference to the value itself rather than a pointer to it’s object. If i do:

ctrl = $.pos.controller
ctrl = position_script()

The pointer will get the script controller and not the value itself, where as a reference is ‘direct assignment’. So:

ctrl = &$.pos.controller 
ctrl = position_script()

will work. I’ve used it in just 2-3 libs so far, mainly for controller assignment but also overriding arrays in recursive functions.

I didnt know about the ‘*’ dereferencing operation – thats handy to get the references value.

ctrl = &$.pos.controller
*ctrl when outside of a function call and (*ctrl) when inside eg. fn a (*ctrl) b

‘&’ is classOf valueRef (value reference)

http://docs.autodesk.com/3DSMAX/14/ENU/MAXScript%20Help%202012/

Excellent,
yea… i would have never found or would think of it as a new valueRef class

Thanks Charles

eek, Do you know why the second one doesn’t pass by reference? I can’t see why…

(
	fn test &ref: = format "Variable by reference: %
" ref
	
	val = &$.radius
	test ref:&val
)

(
	fn test &ref: = format "Property by reference: %
" ref
	
	test ref:&$.radius
)
Variable by reference: (prop radius* (%"getDollarSel"()))
OK
Property by reference: 14.0067
OK

i started to write this the other day but was too busy at work to finish it:

normally, without the ampersand &, the variable ‘TheArray’ in your function would be a copy of the variable passed to it, in this case ‘aa’. This means that you can modify the variable ‘TheArray’ without affecting ‘aa’.

most of the time, at least in maxscript, this is what you want
for example consider:

fn GetSquareByValue val =
 (
 val *= val
 val
 )
 fn GetSquareByReference &val =
 (
 val *= val
 val
 )
 myVal = 2
 mySquare = GetSquareByValue myVal  -- return value is 4
 mySquare2 = GetSquareByReference &myVal  -- return value is 4 but myVal will also be 4
 error = GetSquareByReference &2 -- this does not work, can't get a reference to a literal value

myVal does not change with each call to GetSquareByValue but it does change with each call to GetSquareByReference.
Also note how passing literal values by reference is not possible.

So hopefully this shows how passing by value passes a copy of the value to a function and passing by reference passes a reference to the variable holding the value

1 Reply
(@denist)
Joined: 10 months ago

Posts: 0

this is not true… ALWAYS when you pass pointer type value (array, structure, string, point2, poin3, point4, etc…) as a function’s argument it passes the exact pointer to the variable (not a copy).


 (
 	local arr = #(1,2,3)
 	fn addtoarray a i = 
 	(
 		append a i
 		ok
 	)
 	addtoarray arr 4
 	format "array:%
" arr
 
 	local ptr = [1,2,3]
 	fn addtopoint p i k:1 = 
 	(
 		p[k] = i
 		ok
 	)
 	addtopoint ptr 4
 	format "point:%
" ptr
 
 	local str = "abc"
 	fn addtostring s i k: = 
 	(
 		s[k] = i
 		ok
 	)
 	addtostring str "d" k:str.count
 	format "string:%
" str
 )
 

Great explanation Joel,
Cheers

 eek

From my understanding…
So the ‘&’ is a pass-by-reference to the value, which you’ve set as an argument. So by passing a pass-by-reference to this argument itself again you essentially turning it into a pointer. If we have functions:

fn test &ref: = ...

In this case we’ve made our pass by reference as an argument. We don’t need to make a pass by reference to the value. We can just call the property like so:

val = $.radius
test &ref:val

Denis – i think either you misunderstood what i was trying to say or i wasn’t clear enough.

The original post was regarding direct assignment to the parameter of a function not affecting the original variable.

I think what I need to clarify when I said: 

is that the ‘value’ in the case of a pointer type is actually a pointer and not the value it points to.

eg:
fn ModifyArray a =
    (
    append a 4
    a = #(9,8,7)
    OK
    )
    arr = #(1,2,3)
    ModifyArray arr

at the start of the function, ‘a’ points to the same array as ‘arr’

append a 4
– this appends ‘4’ to the array pointed to by ‘a’ which also happens to be the array pointed to by ‘arr’

a = #(9,8,7) – ‘a’ now points to a newly created array #(9,8,7) meaning that ‘a’ no longer points to the same array as ‘arr’. This assignment does NOT affect the original variable ‘arr’.
Any further changes to ‘a’ at this point will not affect ‘arr’

now if you were to use the ampersand like so:

fn ModifyArray [b]&[/b]a =
  ...
  ModifyArray [b]&[/b]arr

the result of the function would be that ‘arr’ now points to the array #(9,8,7) since it was passed by reference.

Hope this clears everything up.

a = #(9,8,7) – ‘a’ now points to a newly created array #(9,8,7) meaning that ‘a’ no longer points to the same array as ‘arr’.

that’s correct. but it’s a result of other function – “=”. assignment.
as you see we doesn’t pass any reference in this function. so the “=” function works as expected for this class. This functions works specifically for different classes. For an Array it works one way, for a ValueRef another.

 eek

Crucially it’s whether the operation on the pointer changes its address or not.