Go to the first, previous, next, last section, table of contents.

Specifying Function Arity

The Muq assembler computes the number of arguments accepted and returned by the function being assembled -- the arity of the function -- and saves it in the associated function object.

Some languages allow the user to explicitly declare the arity, in which case it may make sense to supply this declared information to the assembler for cross-check purposes.

There may also be cases where the assembler is unable to compute the arity, or where you wish to override the computed arity with an explicitly specified one -- for example, when the function hasn't been written yet, and only a preliminary stub is being compiled.

Muq encodes the arity information for a function as a single integer, for speed of runtime checking. The arity has five logical components:

  1. Blocks consumed/used as input.
  2. Blocks returned as output.
  3. Normal (nonblock) args consumed/used as input.
  4. Normal (nonblock) args returned as output.
  5. Function type.

Where "Function type" is a catchall slot for indicating other information of interest about the function. It will currently be one of:

0  arityNormal		A vanilla function.
1  arityExit		This function never returns to caller.
2  arityBranch		A bytecode that alters the program counter.
3  arityOther  	I'm not sure this is used.
4  arityCalli		Special hack for JOB_OP_CALLI bytecode.
5  arityQ		Function returns unpredictable number of args.
6  arityStartBlock	Special hack for '[' operator.
7  arityEndBlock	Special hack for '|' operator.
8  arityEatBlock	Special hack for ']' operator.
9  arityCalla		Special hack for JOB_OP_CALLA bytecode.
10 arityCallMethod	Special hack for JOB_OP_CALL_METHOD bytecode.

The specific decimal values given are subject to change in future releases: Use the given symbolic constant names instead.

These constants are defined in `muq/muf/10-C-utils.t' and `muq/c/fun2.h', which also define the layout of an arity word:

/* The current layout looks like:                   */
/*						    */
/*   MSB 33222222222211111111110000000000 LSB	    */
/*       10987654321098765432109876543210	    */
/*        S-----Ss-----sB----Bb----bt--tI	    */
/*						    */
/* where:					    */
/*   I:       1-bit typetag identifying integers.   */
/*   t--t:    4-bit type (see FUN_ARITY_TYP_*).	    */
/*   b----b:  6-bit count of stackblocks accepted.  */
/*   B----B:  6-bit count of stackblocks returned.  */
/*   s-----s: 7-bit count of scalar args accepted.  */
/*   S-----S: 7-bit count of scalar args returned.  */

(Again, this layout is subject to change in future release: Use implodeArity to construct arity values, rather than hardwiring assumptions about the layout into your code. See section `implodeArity' in implodeArity.)

Thus, if your function accepts two blocks and three normal arguments, and returns one block and zero normal arguments, you may construct an appropriate arity value for it via

2 3 1 0 arityNormal implodeArity -> arity

And the final argument to finishAssembly?

It is an force flag which may be set non-NIL to force the assembler to accept the arity value you supply as valid, rather than conducting its own cross-check.

And what if you want to let the assembler compute the function arity on its own, and ignore your value? In this case, provide an arity of -1 and leave the force argument NIL.

Bottom-line take-home lesson for this section: 99% of the time, you can supply NIL as the force argument and -1 as the arity argument, and everything will go fine.

Ok, enough discussion of how to assemble the trivial function: Let's assemble some functions which actually things!

Go to the first, previous, next, last section, table of contents.