a = 1;
b = 2;
type( a + b );
"Number"
Internally, type received an expression tree that looks like add( a, b ). The tree is evaluated to a number.
a = 1;
b = 2;
type( expr( a + b ) );
"Expression"
Internally, type received an expression tree that looks like expr( add( a, b ) ). Again, the tree is evaluated; the expr() node in the tree returns its argument as an expression.
a = 1;
b = 2;
c = expr( a + b );
type( c );
"Number"
Internally, type received an expression tree that looks like c. Again, it is evaluated. c is an expression, add(a,b), that will use the current values of a and b whenever c is evaluated. c does NOT have an expr() node in its tree.
"unpacking" isn't a well defined idea in JSL. Every built in function initially sees its argument(s) as expression trees. Some functions evaluate their arguments without looking at them first. Other functions never evaluate them. Some functions look to see if the root node of the expression is eval() or expr() or send() and do something different. (send() is the << operator. There is a unary usage in argument lists to identify special arguments, oftentimes actual messages being sent to a displaybox that is being created.) Adding a formula expression to a column is one example that trips me up sometimes; it assumes the argument should not be evaluated. Adding eval() around the formula causes it to eval, because formula(...) peeks at the argument. The alternative would have been to always evaluate the argument and then the normal use case would require expr() around the formula (because evaluating expr(...) just returns its argument.)
Craige