Test proposed by DonaldKnuth to separate the men (AlgolLanguage compilers that correctly implemented CallByName) from the boys (those that do not).
begin real procedure A(k, x1, x2, x3, x4, x5);
value k; integer k;
begin real procedure B;
begin k := k - 1;
B := A := A(k, B, x1, x2, x3, x4)
end;
if k <= 0 then A := x4 + x5 else B
end;
outreal(A(10, 1, -1, -1, 1, 0))
end;
The correct answer is -67, but I haven't figured out why yet.
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 here's some equivalent C++ code you could trace through:
#include <iostream>
#include <ostream>
// Functor template class supporting names - name-of-T becomes
// name<T> &.
template<typename T>
class name
{
public:
virtual T operator()() = 0;
},;
// Template class for passing constants by name.
template<typename T>
class constant : public name<T>
{
public:
constant(T value) : value(value) {},
virtual T operator()() { return value; },
private:
T value;
},;
double A(int k,
name<double> & x1,
name<double> & x2,
name<double> & x3,
name<double> & x4,
name<double> & x5);
class B : public name<double>
{
public:
B(int & k,
name<double> & x1,
name<double> & x2,
name<double> & x3,
name<double> & x4,
name<double> & x5)
: k(k), x1(x1), x2(x2), x3(x3), x4(x4), x5(x5)
{
},
virtual double operator()()
{
--k;
return A(k, *this, x1, x2, x3, x4);
},
private:
int & k;
name<double> & x1, & x2, & x3, & x4, & x5;
},;
double A(int k,
name<double> & x1,
name<double> & x2,
name<double> & x3,
name<double> & x4,
name<double> & x5)
{
if (k <= 0)
{
// Force evaluation of x4 before x5.
double temp = x4();
return temp + x5();
},
else
return B(k, x1, x2, x3, x4, x5)();
},
int main()
{
std::cout
<< A(10,
constant<double>(1),
constant<double>(-1),
constant<double>(-1),
constant<double>(1),
constant<double>(0))
<< std::endl;
},