cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Try the Materials Informatics Toolkit, which is designed to easily handle SMILES data. This and other helpful add-ins are available in the JMP® Marketplace
Choose Language Hide Translation Bar
Write Your Own Functions

Problem

You have some code that you want to call from more than one place, maybe with different arguments.

Solution

Use a user written function, with parameters, local variables to keep them away from other code, and a return statement to send back an answer.

// this example shows how to write a user written function to roll 
// ndice with nsides

// a user written function is created with an assignment statement
// to a variable that will be the name of the function. rollDice
// seems a good name to explain what this function does.

rollDice = Function( {ndice = 2, nsides = 6}, // parameters
    {i, sum = 0}, // local variables
    For( i = 1, i <= ndice, i++, // loop to add up the rolls
        sum += Random Integer( 1, nsides ) // one roll
    ); // end of the loop
    Return( sum ); // value to return
); // end of the definition

// make table and distributions. the number of dice 
// and the number of sides is chosen to make the
// average roll be 36

dt = New Table( "Untitled",
    Add Rows( 10000 ),
    // each column has a formula that calls the function...
    New Column( "one", Formula( rollDice( 1, 71 ) ) ),
    New Column( "two", Formula( rollDice( 2, 35 ) ) ),
    New Column( "three", Formula( rollDice( 3, 23 ) ) ),
    New Column( "four", Formula( rollDice( 4, 17 ) ) )
);

// check the Std Dev in the 4 reports...
// it gets smaller with more dice

dt << Distribution(
    Continuous Distribution( Column( :one ) ),
    Continuous Distribution( Column( :two ) ),
    Continuous Distribution( Column( :three ) ),
    Continuous Distribution( Column( :four ) ),
    SendToReport(
        Dispatch( {"one"}, "Distrib Histogram", FrameBox, {DispatchSeg( Hist Seg( 1 ), Bin Span( 24, 0 ) )} ),
        Dispatch( {"two"}, "Distrib Histogram", FrameBox, {DispatchSeg( Hist Seg( 1 ), Bin Span( 24, 0 ) )} ),
        Dispatch( {"three"}, "Distrib Histogram", FrameBox, {DispatchSeg( Hist Seg( 1 ), Bin Span( 24, 0 ) )} ),
        Dispatch( {"four"}, "Distrib Histogram", FrameBox, {DispatchSeg( Hist Seg( 1 ), Bin Span( 24, 0 ) )} )
    )
);
More dice, smaller standard deviationMore dice, smaller standard deviation

Discussion

The Function() function returns a function. The first argument to Function() is a list of parameters, and is required. Use {} if you have no parameters. The parameters can have default values as shown above; rollDice() will use two 6-sided dice. rollDice(3) will use three 6-sided dice, and rollDice(1,7) uses one 7-sided die.

The second argument to function is an optional list of local variables, which can have initial values. By using local values, you can have functions call other functions and not worry about reusing "i" in a for-loop. If you don't need to specify locals, just put the function body as the 2nd argument rather than the third.

The final argument (2nd or 3rd) is the function body. It can reference global values if needed. You can use a return statement anywhere in the body to specify a value to send back to the caller. If there is no return statement, the value of the last statement executed is returned.

The function rollDice is not executed when it is first defined. It is executed when it is called with arguments, like

rollDice(3,6)

which the example does in the column formulas.


See Also

http://www.jmp.com/support/help/Advanced_Programming_Concepts.shtml

Comments
Judah

Thanks for this, @Craige_Hales.  When calling the rollDice function, is there a way keep ndice equal to its default value and setting nsides equal to a non-default value without passing in the default value of ndice?

 

For example:

ndice = 3, nsides = 5  ==>  rollDice( 3, 5 )

ndice = 3, nsides = 6 (default value)  ==>  rollDice( 3 )

ndice = 2 (default value), nsides = 5  ==>  rollDice( ?? )

 

Of course, ndice could be specified ( rollDice( 2, 5 ) ), but does it have to be to allow a non-default value for nsides to be used?

Thanks! @Judah

 

I'd probably make a rule for a missing value and add an if statement to replace missing with default. rollDice( . , 5 ); which probably means two copies of the default value in the function...

 

There are several reasons for using default values, and some of them might be bad reasons, sometimes.

  • making calling code shorter
  • being able to change the default later, in one place
  • because the function was change after it was first published
  • ?

The default parameters are probably not any faster than specifying them (untested guess.) It may look better if the default values are what a reasonable code reviewer would expect. Changing the default later might break something. Adding a new parameter for a new caller and not touching the old callers might be useful.

 

I might be wishing I'd left the default values out of this example; they don't always make code easier to follow. Power tools!

Judah

@Craige_Hales

FWIW, I'm glad you left the default values in your example.  I came across this post when I was searching for some info on Function(), and this was quite helpful!

JSL Cookbook

If you’re looking for a code snippet or design pattern that performs a common task for your JSL project, the JSL Cookbook is for you.

This knowledge base contains building blocks of JSL code that you can use to reduce the amount of coding you have to do yourself.

It's also a great place to learn from the experts how to use JSL in new ways, with best practices.