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; }