[gclist] Finalization and object orientation.

Richard A. O'Keefe ok@cs.rmit.edu.au
Wed, 2 Apr 1997 12:42:15 +1000 (EST)


	Consider the following ML function (simulating N phases of a typical 
	compiler):

	      fun compile (src) =
	        let val codeInIL1 = phase1(src)
	            val codeInIL2 = phase2(codeInIL1)
	            ......
	            val codeInILN = phaseN(codeInILNm1)

	         in codeInILN
	        end

	What we concluded is the following: for languages that make pervasive uses
	of "functions" and/or "closures", a new scoping rule must be used. Each 
	local variable should be considered "dead" after its *last* use in the 
	current function body. By "dead", I really mean "not contributing to the 
	liveness of the data structure it points to".

Let me put this in Prolog terms:

	compile(T0, T) :-
	    phase1(T0, T1),
	    phase2(T1, T2),
	    ...,
	    phaseN(Tn, T).

David Warren, in the early 80s spoke of "environment trimming";
his Prolog compiler (based on the WAM, it became Quintus Prolog)
basically does

	T1 := unbound
	...
	Tn := unbound
	R1 := T0, R2 := T1
	*remove T0 from the environment if possible
	call phase1/2
	...
	R1 := Tn, R2 := T
	*remove the entire environment if possible
	jump phaseN/2

The "if possible" refers to the need to handle backtracking.
(I don't know what the Mercury compiler does, but since it has more
information, it should do even better.)

To this day Quintus Prolog continues to do this.  It's particularly
important in a logic programming language, because you get a lot more
variables than you would in a functional language.