Jensen's Device owes its name to Kathleen Jensen
, co-author with Niklaus Wirth
of the Pascal
User Manual and Report.
Jensen's Device came about through a creative interpretation of the Algol 60
programming language standard as it was being defined.
The standard set about defining calling conventions for procedures.
In this, there were two parameter passing mechanisms:
Expressions are evaluated, and the values are assigned
to the formal parameter variables. You are permitted to change the formal parameters inside
the procedure, but this has no effect on the caller's environment.
- By name
The parameter is evaluated in the context where it is used
in the calling code. The variable may be referred to inside the procedure as an lvalue or rvalue.
The subtleties of pass by name were overlooked by early language implementers, and
it was only when Jensen's device was published, that they realised that
extra effort was required to implement the Algol 60 standard as written. The subsequent implementations
usually involved passing a parse tree, with extra semantics for when this is interpreted as
lvalue and rvalue. A more tidy way of achieving the same thing is to use a "thunk" or closure.
Jensen's Device fell into disrepute, being slated as obfuscation and leading to misunderstandings and buggy code. None of the successor languages of Algol 60, apart from Algol W,
had pass by name. They adopted pass by reference, which was in widespread use in
Fortran. However, the Ruby language has full scale calling by name, and implements Jensen's
Device (but calls this an iterator).
Jensen's Device example
comment This is a simple example of Jensen's device;
comment This takes the sum of expr from lo to hi, inclusive.
The variable index is incremented through the range.;
real procedure sum(lo, hi, index, expr);
value lo, hi;
integer lo, hi, index;
comment initialize accum to zero and add the terms.;
accum := 0.0;
for index := lo step 1 until hi do begin
accum := accum + expr
sum := accum
comment Sum of integers, 1 to 20.;
outreal(1, sum(1, 20, i, i));
comment sum of 10 die rolls;
outreal(1, sum(1, 10, i, rand MOD 6));
comment mean and variance;
real array data;
real mean, sumd, sumsq;
for i:=1 step 1 until 10 do
sumd = sum(1, 10, i, data[i]);
sumsq = sum(1, 10, i, data[i]*data[i]);
outstring(1, "Mean is: ");
mean = sumd / 10.0;
outreal(1, mean );
outstring(1, "Variance is :");
outreal(1, sumsq / 10.0 - mean * mean);