Changes by: Jason Hickey (jyh at cs.caltech.edu)
Date: 2005-08-30 20:35:58 -0700 (Tue, 30 Aug 2005)
Revision: 1440
Log message:
This is a solution to the "export problem."
So here was the problem. Suppose you take a higher-order function (that
part is no big deal), but the function ends in an export.
In the non-higher-order case, there is no problem.
X. =
Z = 1
f() =
Z = $(add $Z, 1)
export
# This redefines X as a new object with Z=2
X.f()
But suppose the method escapes.
X. = ...same as before...
# Create a closure
g = $(X.f)
# Call the function, but it exports...
g()
Well, what does the export in g() mean? X isn't mentioned, so it would
be a sad thing to redefine X. It would be even worse (as it is on the
trunk) if the export meant that now Z is defined after the call g().
It could be prevented by disallowing exports from higher-order functions
entirely. But we also have cases where we expect the export to be
effective.
text[] =
foreach(x => a b c)
text[] += $(x)
export
# We expect this to print "a b c"
println($(text))
This commit is permissive about exports. Each scope is assigned an identifier,
and exports are allowed only in identical scopes.
File-level variables are no problem, they are always exported. Object
public/protected variables are exported only within the same object.
Private variables are exported only within the same scope/function body.
This means that the export in the g() above is ineffective.
It also means that private exports also work as expected.
f() =
private.text =
foreach(x => a b c)
text += $(x)
export
# Prints "a b c"
println($(x))
In the next example, the export is ineffective.
g() =
private.x = 1
export
f() =
g()
# This is a link error
println($(x))
Private variables are lexically scoped, as usual. Protected/public have
the usual late-binding meaning. File variables (that is, top-level
variables in a file) are dynamically scoped.
The program in this file will print "2", then "1".
X = 1
g() =
println($(X))
f() =
X = 2
# Prints "2"
g()
# Prints "1"
g()
The program in this file will print "1", then "1".
private.X = 1
g() =
println($(X))
f() =
X = 2
# Prints "1" (private variables are lexically scoped)
g()
# Prints "1"
g()
New definitions in a function body are private by default (so are
the parameters).
File1.om:
X = 1
g() =
println($(X))
File2.om:
import File1
f() =
X = 2 # This new definition is for private.X in f()
File1.g() # This prints "1"
File3.om:
open File1
f() =
X = 2 # This refers to File1.X
g() # This prints "2"