How to order the arguments in Forth

How to choose arguments order? Good question! In Forth this question should cover the order of results as well.

Obviously any rules should have some rationales. They can be a consequence of some basic principles or should solve some problems.

I think we can start from convenience of code reusing (any source code fragment, including any single word). The essential formal parts of this convenience are consistency and source code minimization.

Regarding the arguments order these parts have the following meaning.

  • Consistency: we should use the similar order in the similar cases (more formal: retain an substantial isomorphism among the similar cases).
  • Minimization: we should choose an order that minimizes overall size of a source code (i.e., less stack manipulations).

So, at the first, we should be consistent with the existing conventions (or with existing code), and at the second — find optimal ordering. Of course, there can be exceptions when some old code uses inconsistent convention.

Some of the known conventions can be found in the famous "Thinking Forth" by Leo Brodie:

Let addresses precede counts. (Tip 4.18)

Example: ERASE ( addr u -- )

Let sources precede destinations. (Tip 4.19)

Example: MOVE ( source destination count -- )

There is also one well known rule that is not only a convention but also an optimization (confirmed by practice).

Let less permanent arguments precede more permanent.

Usually it leads to less stack manipulations. This rule can be found in many many standard words. For example, WRITE-FILE ( addr u file-id -- ior ) or SEARCH-WORDLIST ( addr u wid -- 0 | xt flag ) — there file-id and wid are more permanent than addr u pair. More permanent arguments are tended to be kept in variables on a topper level and so there is easier to pass them as top argument. Example: ... GET-CURRENT SEARCH-WORDLIST ...

This rule is also implicitly reflected in the following tip from Leo Brodie

  • When determining which arguments to handle via data structures rather than via the stack, choose the arguments that are the more permanent or that represent a current state. (Tip 7.3)

In case of the results this rule become inverse.

For returned items, let more permanent item precede less permanent.

For example, ior, flag, etc — are usually returned on the top.

Variations

In some cases it is convenient to have several variants. For example, standard words ROT and -ROT. Other examples:

\ different order of inputs
FOR-LIST-NODE ( list xt -- )
FOREACH-LIST-NODE ( xt list -- )

\ different order of outputs
SPLIT ( d-txt d-key -- d-txt false | d-left d-right true )
SPLIT- ( d-txt d-key -- d-txt false | d-right d-left true )

The ! way you mentioned of : SERVO! ( val #ch -- ) is probably the best, since you don't need to mentally keep track of which servo you are using while calculating the value you want the servo to move to.

Also, since it's similar to ! (you're storing a value into the servo), and you're naming the word SERVO!, it would be confusing if the parameter order were opposite of !.

Tags:

Forth