Call-by-Reference

The feature of call-by-reference in ATS is similar to the corresponding one in C++. What is special in ATS is the way in which this feature is handled by the type system. In general, if f is given a type of the following form for some viewtypes VT1 and VT2:

(..., &VT1 >> VT2, ...) -> ...

then a function call f(..., lval, ...) on some left-value lval of the viewtype VT1 is to change the viewtype of lval into VT2 upon its return. In the case where VT1 and VT2 are the same, &VT1 >> VT2 may simply be written as &VT1.

As an example, an implementation of the factorial function is given as follows that makes use of call-by-reference:

fun fact (x: int): int = let
  fun loop {l:addr} (x: int, res: &int): void =
    if x > 0 then (res := res * x; loop (x-1, res)) else ()
  var res: int = 1 // [res] is a variable!
in
  loop (x, res); res
end // end of [fact]

Note that if the line for introducing the variable res in the above implementation is replaced with the following one:

  val res: int = 1 // [res] is no longer a variable but a value!

then a type error is to be reported as res is no longer a left-value when it is passed as an argument to loop.

In functional programming, optional types are often used for error-handling. For instance, the following function divopt returns a value of the type Option(int) that either contains the result of the division or indicates a case of division-by-zero:

fun divopt
  (x: int, y: int): Option (int) =
  if y != 0 then Some (x/y) else None ()
// end of [divopt]

Given that a value of the form Some(v) is heap-allocated, the memory for storing it can only be reclaimed by garbage collection (GC). In other words, the memory is leaked if GC is not available. To address the issue of error-handing in the absence of GC, we can employ call-by-reference as is shown below:

fun diverr (
  x: int, y: int, err: &int
) : int =
  if y != 0 then x/y else (err := err+1; 0(*meaningless*))
// end of [diverr]

We can tell whether division-by-zero has occurred by comparing the values of err before and after a call to diverr. This style of error-handling is commonly seen in code written in languages like C.