cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Choose Language Hide Translation Bar

Keyword arguments for functions

I would love if in User Defined funcitons we could use keyword arguments in the calls so I can do

Names default to here(1);
f = function({x, y=2, z=3}, 
	show(x, y, z);
);
print("What I'd like to do");
f(1, z=2);
//I want it to be 1, 2, 2

//instead of having to do 
f = function({x, kwargs={}},
	{DEFAULT LOCAL}, 
	// optional
	y = 2;
	z = 3;
	evallist(kwargs);
	show(x, y, z);	
);
print("Using List");
f(1, {z=2});

Someone mentioned it here, but it was 8 years ago, so figured I'd bring it up again.  

15 Comments
gzmorgan0
Super User (Alumni)

@vince_faller 

 

Cool example. Thanks for Sharing. Typo correction

show(f(2, {y=14})); // 36 not 33

 

hogi
Level XI

How are the standard Jmp functions defined,

- such that close accepts an supplementary argument noSave.

- such that add column accepts the expression Formula(...) at any position within (...)

dt << New Column( "X", Formula( row() ) );

Instead of 

f(2, {y=14})

could 

f(2, y(14))

be the way how it should look like?

Craige_Hales
Super User

The internal functions are built in C++, not JSL. The user functions (in JSL) are interpreted by other C++ code that chooses how to  turn arguments into parameters (where the arguments to a function are the external values passed in and the function's parameters are the internal variable names that refer to the values.)

A function like sin(A), written in C++, looks something like

ExpressionPointer sin( ExpressionPointer E) {
   double value = evaluateExpression( E );
   double answer = sin( value );
   return makeExpression( answer );
}

The expr() function in JSL, where the function just returns its argument without studying it, looks something like

ExpressionPointer expr( ExpressionPtr E ) {
   return E;
}

That seem useless at first glance, but it allows the assignment operator to evaluate the right-hand-side of

ex = expr( a + b );

and store an expression tree into ex rather than the result of a+b. A more interesting example is the head(a+b) operator.

ExpressionPointer head( ExpressionPointer E ) {
   return MakeExpression( E->child );
}

That's a crude approximation of the idea: an expression tree for a+b has a root, +, which has two children, a and b.  E->child is getting the root, +, and returning that as an expression with no children.

The JMP developers made a decision to hide that complexity in the JSL user written functions to make the 99% use cases easy to write. Most of the languages I'm familiar with don't have expressions that can be manipulated (Snobol does, sort of, and that explains JMP's patmatch() function...) Using a list is a reasonable approach to sending an expression to a function; the list is evaluated...to the same list. The function is working on a copy of the list.

 

Status changed to: Acknowledged
 
hogi
Level XI

The trick with the list is very useful.
Actually, evaluating the list is not really needed to access the variables.

One can scan the list and search for the right name. either by a for each loop or via Extract Expr.

 

Names default to here(1);

get = Function ({var}, Eval(Eval Expr(Arg(Extract Expr(kwarg,  Expr(Name Expr(var)) = wild()),2))));

f = function({x, kwargs={}},
	{DEFAULT LOCAL}, 
	print(get(Expr(z)));
);

f(1, {z=2});