[comp.lang.modula3] Structure return

X903%DMAFHT1.BITNET@CUNYVM.CUNY.EDU (Marc Wachowitz) (04/19/91)

Recently there were comments saying returning structures were difficult
to implement or inefficient. I don't think this is the case. Just have
the caller suplly the address where the result is expected. If it's a
variable (i.e. the call was of the form  variable := Func() ), the
final code is the same as with VAR parameters, so it's obviously not
particularly difficult or inefficient. If the call is part of an
expression (which implies it's the argument of another procedure call),
the caller just allocates the space for the argument on the call stack
and passes its address to the structure-returning procedure. There is no
temporary local variable in the callee, access goes through this address.
So it's again the same as a VAR parameter. The only difference is that
you don't need to supply variables explicitly, but they are implicitly
allocated by the compiler on the call stack, which is probably not very
expensive.

Example, which also shows the usefulnes of structure returns, assuming
there's a notation for structure values (meaning should be obvious):

TYPE Complex = RECORD re, im: REAL END;
PROCEDURE Sum(a, b: Complex): Complex;
  BEGIN
    RETURN Complex(a.re + b.re, a.im + b.im)
  END Sum;

Similar definition for PROCEDURE Prod(a, b: Complex): Complex;

Now you can write expressions like a := Sum(x, Prod(y, z)) similar
to normal formulae (a := x + y * z).

With VAR parameters only you had to write:

PROCEDURE Add(VAR a: Complex; b: Complex);
  BEGIN
    a.re := a.re + b.re;
    a.im := a.im + b.im;
  END Sum;

Similar for PROCEDURE Mul(VAR a: Complex; b: Complex);

VAR temp: Complex;
...
a := y;
Mul(a, z);
Add(a, x);

Now imagine the expression were much more complex. You would end up
playing the role for a FORmular TRANslator, instead of the compiler
doing such simple things for you.

Using pointers instead does provide for the same notation as the
value passing method, but the performance penalty may be high if
you must (read: cannot) cooperate with a traditional environment
of library functions etc. This would only change if all variables
were pointers (as in LISP systems), which would allow the application
of generational incremental garbage collection. As far as I know,
there's yet no implementation of this for "uncooperative" environments.