PDA

View Full Version : Using a function with arguments as an argument for a function - how?


eek
12-17-2008, 11:38 PM
Is the only way for a function with arguments to be used as an argument to a function, is if its encapsulated?

for example:


fn testB a b = (messagebox ((a+b) as string))

fn testA theFunction n =
(
if (n != false) then
(
theFunction()
)
)

testA (testB 10 20) false


will still return the message box, even though its set to false. Now if i encapsulate the function inside another,

fn testB a b = (messagebox ((a+b) as string))

(
local localFunction = fn test = (testB 20 30)

fn testA theFunction n =
(
if (n != false) then
(
theFunction()
)
)
testA test false
)


it works. Anyone know whats going on?

ZeBoxx2
12-17-2008, 11:55 PM
whenever you use the function name with arguments, you're actually calling the function already. You're not passing a function name + its arguments to another function.

e.g.


fn testB a b = (messagebox ((a+b) as string))
fn testA theFunction n =
(
if (n != false) then
(
theFunction()
)
)
testA (testB 10 20) false


actually gets run as:

fn testB a b = (messagebox ((a+b) as string))
fn testA OK n =
(
if (n != false) then
(
OK()
)
)
testA (OK) false


You'll find, in fact, that if you pass 'true' ast the last parameter to testA, it will throw an error, as OK is not a function.

-- Error occurred in testA()
-- Frame:
-- n: true
-- theFunction: OK
-- Type error: Call needs function or class, got: OK



The second one has much the same problem...


fn testB a b = (messagebox ((a+b) as string))
(
local localFunction = fn test = (testB 20 30)
fn testA theFunction n = (
if (n != false) then (
theFunction()
)
)
testA test false
)


is...


fn testB a b = (messagebox ((a+b) as string))
(
local localFunction = fn test = (OK)
-- localFunction now points to function test
fn testA theFunction n = (
if (n != false) then (
-- This time you can call it with 'true' as well
-- as the result of test() is OK
theFunction()
)
)
testA test false
)


==================================================

What you'd want is to actualy add the parameter names of your first function to the second function, and supply the first function with all the parameters the second function would need. Then call the 2nd function with those parameters from the first function.
... have some tea :)


fn testB a b = (messagebox ((a+b) as string))
fn testA n theFunction a b = (
if (n != false) then (
theFunction a b
)
)
testB()
testA()
testA false testB 10 20
undefined
testA true testB 10 20
-- messagebox pops up
OK


There's other methods... storing the parameters in variables means you don't have to supply them to the first function, for example - but you do end up using variables


fn testB = (messagebox ((a+b) as string))
fn testA n func = (
if (n != false) then (
func()
)
)
-- these variables must exist in a scope known to testB.
-- This is all in the MaxScript Listener, so a global scope. Ew.
a = 10
b = 50
testA false testB
testA true testB


Here's some other insane methods.

Execute: requires the function being called to be explicitly referred to -or- be defined in a global scope.

fn testB a b = (messagebox ((a+b) as string))
fn testA n theFunctionWithParameters = (
if (n != false) then (
execute theFunctionWithParameters
)
)
testA false "testB 10 20"
testA true "testB 10 20"


Feeding the function + its parameters as an array (they're coming to take me away, ha-HA!)

fn testB a b = (messagebox ((a+b) as string))
fn testA n func = (
if (n != false) then (
func[1] func[2] func[3]
)
)
testA false #(testB,10,20)
testA true #(testB,10,20)

drdubosc
12-18-2008, 12:07 AM
To ensure "testB 10 20" is interpreted as a closure, rather than being evaluated, can't you just do this?


fn testB a b = (messagebox ((a+b) as string))

fn testA theFunction n =
(
if (n != false) then
(
theFunction()
)
)

fn testC = testB 10 20

testA testC false

ZeBoxx2
12-18-2008, 12:13 AM
To ensure "testB 10 20" is interpreted as a closure, rather than being evaluated, can't you just do this?
Yep - but then how are you going to feed it values other than 10 and 20? the '10 20' is now hardcoded in testC :curious:

eek
12-18-2008, 12:15 AM
To the first reply:

Cool, I get that, but your still essentially encapsulating the variables/arguments in the main script. How would you allow the main function to call any other function with variables/arguments/parameters?

I.e testB isnt a one off, working solely with TestA - I want testA to use any function that has variables/arguments. I dont want to have to re-write testA to support a different function with different arguments.

To the second:

exactly - it seems with both these methods max wont support functions with dynamic functions as arguments. I.e testA theFunction <- this could be anything with any numbers of arguments.

ZeBoxx2
12-18-2008, 12:33 AM
Cool, I get that, but your still essentially encapsulating the variables/arguments in the main script. How would you allow the main function to call any other function with variables/arguments/parameters?
As per the example code I gave. The only limitation you will have is that you cannot specify a variable number of parameters.
You -could- semi-do that...


fn testB p1: p2: = ( messagebox ((p1+p2) as string) )

fn testC p1: p2: p3: p4: = (messageBox (((p1*p2)-p3+p4) as string))

fn testA f p1: p2: p3: p4: p5 = (
f p1:p1 p2:p2 p3:p3 p4:p4 p5:p5
)

testA testB p1:1 p2:2

testA testC p1:1 p2:2 p3:5 p4:7

But I'm sure you can tell that gets silly and very chaotic very quickly.

max wont support functions with dynamic functions as arguments.
at least when the number of parameters changes or the function you needs to call gets a bit more complex - correct. The only way around that which is semi-reasonable is the execute method, though you'll still need to escape quotes, etc. for that one to work, or the array method - building the function call string dynamically, then executing it.

eek
12-18-2008, 01:02 AM
at least when the number of parameters changes or the function you needs to call gets a bit more complex - correct. The only way around that which is semi-reasonable is the execute method, though you'll still need to escape quotes, etc. for that one to work, or the array method - building the function call string dynamically, then executing it.

Yes exactly, executing strings is the only way - balls!

ZeBoxx2
12-18-2008, 02:01 AM
Yes exactly, executing strings is the only way - balls!
Well that or the variables thing.. I think I'd typically prefer the variables approach, even if it's no longer passing the parameters, exactly.

Might be good to ask this.. what are you needing this functionality for?

I've only had a few cases where I'd want a variable function to be called from another function (or loop or etc.), and all of those had the same number of base parameters, with optional parameters fed to them via an extraParms: that took an array of values (wich the function then sets to work on)... gets around the fixed number of parameters thing without doing the param1: param2: param3: etc.

eek
12-18-2008, 03:06 AM
Well that or the variables thing.. I think I'd typically prefer the variables approach, even if it's no longer passing the parameters, exactly.

Might be good to ask this.. what are you needing this functionality for?

I've only had a few cases where I'd want a variable function to be called from another function (or loop or etc.), and all of those had the same number of base parameters, with optional parameters fed to them via an extraParms: that took an array of values (wich the function then sets to work on)... gets around the fixed number of parameters thing without doing the param1: param2: param3: etc.

Basically ive built a simple script function which runs on all or only the checked anims of our animation framework 'puppetshop'. Where by you provide the function you want to run on the anims.

I wanted animators or tech guys to be able to supply there own function to be called during the process for example they supply a function that adds 10 frames to each anim, or snaps one object to another on each or checked anim. So thats why i was thinking of this method.

Just trying to become more modular with my approach. Calling execute on strings of say 120 anims one after the other might kill max.

A script or a function without parameters is great, but with causes headaches.

ZeBoxx2
12-18-2008, 09:18 AM
sounds pretty much like a callback function, then..

execute isn't as bad as it is often made out to be... whenever you evaluate a script you're essentially running one big execute ...it's just a tad slower, keeps you stuck in a global scope, and is more annoying to debug. If artists are to supply function names / parameters as well, presumably via an UI, then you're working with text fields that you would have to execute to get the actual function reference anyway.

PEN
12-18-2008, 02:17 PM
If the execute method is the way why not just have them point it all to a script that gets called with a filein? My batch processing tools work this way and it has been great for mass changes on files like you are trying to do.

eek
12-18-2008, 04:42 PM
If the execute method is the way why not just have them point it all to a script that gets called with a filein? My batch processing tools work this way and it has been great for mass changes on files like you are trying to do.

hehe i was exactly thinking this last night - which probably the way to go. The amount of callbacks where currently using is absurd (not from my scripts) - This is more aimed at tech guys, animators would probably just have a list of actions from a rollout they can pick, TD could just add there scripts/functions to a folder and it would pick them up.

Only issue i see with fileIn, is that if theres a function that needs variables such as a snap specified objects over time for example how do you deal with that in the ui? Read the script, do some sort of parameter reading/dynamic ui building?

I guess I'm thinking to laterally, maybe just save the function with the appropriate arguments set then call it. Maybe a temporary version? Would be cool somehow to pull out the arguments of a function into a ui.

PEN
12-18-2008, 07:31 PM
Well you could set it up so that each script is a package that has a function that returns a rollout, if found it would display it so you can change parameters that are local to the script. You can then select and add which scripts you are going to run then select each to see the rollout and make the changes that you need.

CGTalk Moderation
12-18-2008, 07:31 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.