Man or boy test
You are encouraged to solve this task according to the task description, using any language you may know.

Background: The man or boy test was proposed by computer scientist Donald Knuth as a means of evaluating implementations of the ALGOL 60 programming language. The aim of the test was to distinguish compilers that correctly implemented "recursion and non-local references" from those that did not.

I have written the following simple routine, which may separate the 'man-compilers' from the 'boy-compilers' — Donald Knuth

Details: Local variables of routines are often kept in activation records (also call frames). In many languages, these records are kept on a call stack. In Algol (and e.g. in Smalltalk), they are allocated on a heap instead. Hence it is possible to pass references to routines that still can use and update variables from their call environment, even if the routine where those variables are declared already returned. This difference in implementations is sometimes called the Funarg Problem.

In Knuth's example, each call to A allocates an activation record for the variable A. When B is called from A, any access to k now refers to this activation record. Now B in turn calls A, but passes itself as an argument. This argument remains bound to the activation record. This call to A also "shifts" the variables xi by one place, so eventually the argument B (still bound to its particular
activation record) will appear as x4 or x5 in a call to A. If this happens when the expression x4 + x5 is evaluated, then this will again call B, which in turn will update k in the activation record it was originally bound to. As this activation record is shared with other instances of calls to A and B, it will influence the whole computation.

So all the example does is to set up a convoluted calling structure, where updates to k can influence the behavior
in completely different parts of the call tree.

Knuth used this to test the correctness of the compiler, but one can of course also use it to test that other languages can emulate the Algol behavior correctly. If the handling of activation records is correct, the computed value will be −67.

Performance and Memory: Man or Boy is intense and can be pushed to challenge any machine. Memory (both stack and heap) not CPU time is the constraining resource as the recursion creates a proliferation activation records which will quickly exhaust memory and present itself through a stack error. Each language may have ways of adjusting the amount of memory or increasing the recursion depth. Optionally, show how you would make such adjustments.

The table below shows the result, call depths, and total calls for a range of k:

This creates a tree of B call frames that refer to each other and to the containing A call frames, each of which has its own copy of k that changes every time the associated B is called. Trying to work it through on paper is probably fruitless, but the correct answer is −67, despite the fact that in the original paper Knuth postulated it to be −121.

Note that Knuth's code states:

if k <= 0 then A:= x4 + x5 else B;

which actually discards the result value from the call to B. Most of the translated examples below are equivalent to:

A := (if k <= 0 then x4 + x5 else B);

and are therefore strictly incorrect, although in a correct 'man' compiler they do produce the expected result, because Knuth's version has already assigned to the return variable for A from within B, and it is in fact that assignment which is the true return value of the function:

B:= A := A (k, B, x1, x2, x3, x4);

It is most likely that this was a deliberate attempt by Knuth to find yet another way to break 'boy' compilers, rather than merely being sloppy code.

Uses "shared_ptr" smart pointers from Boost / TR1 to automatically deallocate objects. Since we have an object which needs to pass a pointer to itself to another function, we need to use "enable_shared_from_this".

// With Clipper 5.2e compiler and standard RTLINK linker, default settings, only manages up to k=5 before a stack fault:

EVALUATE (0) Unrecoverable error 650: Processor stack fault

// Using Blinker v5.1 it can get up to k=7 by increasing the stack size via BLINKER PROCEDURE DEPTH 74. But that may be the limit for 16-bit Clipper; increasing the procedure depth further does not help, and eventually results in

A (0) Unrecoverable error 667: Eval stack fault

Harbour however is definitely a man: a 32-bit WinXP executable built with Harbour v3.1 and mingw gcc 4.6.1 manages up to k=13 with the default settings. Increasing the stack size (via the Microsoft utility "editbin /STACK:nnn", or "ulimit -s" in linux) allows it to achieve deeper levels:

The DMD compiler is a man. Increasing the maximum stack space to about 1.2 GB the DMD 2.059 compiler computes the result -9479595 for k = 25 in about 6.5 seconds on a 32 bit system (-inline -O -release -L/STACK:1300000000).

If the variadic parameter is an array of delegates with no parameters: void foo(int delegate()[] dgs ...);Then each of the arguments whose type does not match that of the delegate is converted to a delegate. int delegate() dg; foo(1, 3+x, dg, cast(int delegate())null);is the same as: foo( { return 1; }, { return 3+x; }, dg, null );

There are no nested procedures and non-local variables that go with them

There is no selectable call by value .vs. call by name/reference. Knowledge of the implicit mutable/immutable types is needed.

Procedure calls can't be deferred transparently but can be deferred through co-expressions

Co-expressions aren't enough as they trap local copies of variables which follow Icon rules for mutability/immutability

The initial solution below involved the use of co-expressions which seemed a natural tool to solve MoB. It turns out that co-expressions aren't necessary to solve this task. Co-expressions are very powerful and MoB really doesn't exercise their full capability. There is a lighter weight solution and also a cheat solution which is a further simplification. The light weight version exploits that procedures are a data type and can be passed around and assigned. This allows us to defer calling 'B' which is just what is required. The change introduces a new record definition 'defercall' and changes only two lines of the original solution in 'eval' and 'B'. The cheat would be to have 'eval' know that it always called 'B'.

MoB is intense and can be pushed to challenge any machine. If you run this and the program hangs up or fails with an inadequate space for static allocation error, you may need to tweak the way Icon/Unicon allocates memory. This is controlled through the environment variables COEXPSIZE, MSTKSIZE, BLKSIZE (see Icon and Unicon Environment Variables).

Notes:

The co-expression version will require adjustment to COEXPRSIZE, and possibly BLKSIZE and MSTKSIZE.

We emulate the ALGOL60 example as closely as possible. Like most of the examples, we use functions to emulate call-by-name.

Oz variables are immutable, so we use a mutable reference ("cell") for K. The ALGOL example uses call-by-value for K. Oz uses call-by-reference, therefore we copy K explicitly when we call A recursively.

We use explicit "return variables" to emulate the strange behaviour of the ALGOL B procedure which assigns a value to A's return value.

The above PL/I code has been tested on OS PL/I V2.3.0, Enterprise PL/I V3R9M0 and PL/I for Windows V8.0. The limit for OS PL/I on a z/OS machine with 4Gb seems to be A=15, the limit for Enterprise PL/I on the same machine seems to be A=23, and the limit for PL/I for Windows on a 16Gb system seems to be A=26.

The «Russian» compiler (that is based on Kildall’s compiler PL/I-86) produced the best results. However, two tricks were used there: a) hardware stack pointer was set directly to allocated memory by quasi-assembler’s instruction; b) stack of parameters was replaced by array of parameters and contexts. The result is A=27 for Win32 (Windows-XP) and A=31 for Win64 (Windows-7). Source code test for Win32 see: http://rsdn.org/article/pl1/PL1ex7/pl1ex7.xml
In source code test for Win64 FIXED(31) was replaced by FIXED(63) and pseudo-variable ?ESP by ?RSP.

That is, instead of evaluating its arguments normally, A captures their original expressions, and instead of evaluating its body normally, A substitutes calls to evalq the captured argument expressions in the calling frame. After a few levels of recursion this way, you end up evaluating expressions like A(k, B(), evalq(B(), .caller), evalq(evalq(B(), .caller), .caller), evalq(evalq(evalq(1, .caller), .caller), .caller), evalq(evalq(evalq(-1, .caller), .caller), .caller)), so this is not very efficient, but works.

There are two nontrivial features in the "man or boy" test. One is that the parameters x1 though x5 are in general going to be function calls that don't get evaluated until their values are needed for the addition in procedure A, which means that these in Tcl are going to be scripts, and therefore it is necessary to introduce a helper procedure C that returns a constant value. The other is that procedure B needs to refer to variables in the local context of its "parent" instance of procedure A. This is precisely what the upvar core command does, but the absolute target level needs to be embedded into the script that performs the delayed call to procedure B (upvar is more often used with relative levels).

The goal in this solution is to emulate the Algol 60 solution as closely as possible, and not merely get the correct result. For that, we could just crib the Common Lisp or Scheme solution, with more succinct syntax, like this:

To do a proper job, we define a call-by-name system as a set of functions and macros. With these, the function A can be defined as a close transliteration of the Algol, as can the call to A with the integer constants:

We define the global function with defun-cbn ("cbn" stands for "call by name") and the inner function with labels-cbn. These functions are actually macros which call hidden call-by-value functions. The macros create all the necessary thunks out of their argument expressions, and the hidden functions use local macros to provide transparent access to their arguments from their bodies.

Even the fact that a return value is established by an assignment to the function name is simulated. Note that in A and B, we must assign to the variables A and B respectively to establish the return value. This in turn allows the faithful rendition of the detail in the original that the if form discards the value of the call to B. Establishing a return value by assignment, as in Algol, is achieved thanks to the Lisp-2 base of TXR Lisp; we can simultaneously bind a symbol to a function and variable in the same scope.

Also, k is treated as a call-by-name argument also, and is explicitly subject to a rebinding inside A, as is apparently the case in the Algol code. This detail is necessary; if we do not rebind k, then it is a by-name reference to the caller's k, which is a by-name reference to its caller's k and so on.

Call-by-name is achieved by representing arguments as structure objects that hold get/set lambdas, serving as access thunks, hidden behind macros. These thunks allow two-way access: the passed values can be stored, not only accessed. This creates a problem when the actual arguments are constants or function calls; that is solved. Constants are recognized and re-bound to hidden variables, which are passed in their place. Function calls are passed as thunks configured to reject store attempts with a run-time error.

Visual Prolog (like any other Prolog) does not allow variables to be changed. But behavior can easily be mimicked by using a varM (modifiable variable), which is actually an object containing a value of the relevant type in a modifiable entity (a so called fact variable). Secondly, anonymous function (lambda-expression) cannot be recursive, but this is mimicked by using yet a varM to hold the function.

(Token coloring of Visual Prolog in this wiki is unfortunately wrong, because styles are used across languages. A correctly colored version can be seen in Man or boy test in the Visual Prolog wiki).

Adapted from the Lua example. In vorpal, all execution is a message to an object. This task primarily involves functions, so we have the apply the function objects to self for them to execute. Correctly, prints -67.

The compiler is OK but the VM is a girlie-man VM. Due to the way closures are built, the stack blows quickly when closures recurse. So, while the code can be written per Knuth, it is unable to do anything. So, classes are used to simulate the closures. Also (5)()-->5 so no problems there.