Input and Output Top ObjectsScopes, Environments, and Objects Contents

Scopes, Environments, and Objects

A scope holds the current set of variables and their values. As with Scheme, Scam implements scope using environments. For all Scam programs, the built-in functions are stored in the outermost scope, while the functions defined in the main library, main.lib, are stored in the next-to-the-outermost scope. Finally, the user is given a global scope of his or her own. These three scopes make up the global scope for all Scam programs.

One can write a very simple Scam program to see the three levels of the global scope that are in existence for all programs:

    (print "USER SCOPE: ")
    (ppTable this)
    (print "LIBRARY SCOPE: ")
    (ppTable (dot this __context)
    (print "BUILT-IN SCOPE: ")
    (ppTable (dot (dot this __context) __context))

Running this program yields the following output:

    USER SCOPE: <object 8675>
                   __label  : environment
                 __context  : <object 4777>
                   __level  : 0
             __constructor  : nil
                    this  : <object 8675>
                     ...
    LIBRARY SCOPE: <object 4777>
                 __label  : environment
               __context  : <object 62>
                 __level  : 0
           __constructor  : nil
                    this  : <object 4777>
                    code  : <function code($s)>
            stream-null?  : <function stream-null?(s)>
              stream-cdr  : <function stream-cdr(s)>
              stream-car  : <function stream-car(s)>
             cons-stream  : <function cons-stream(# a $b)>
                     ...
    BUILT-IN SCOPE: <object 62>
                 __label  : environment
               __context  : nil
                 __level  : 0
           __constructor  : nil
                    this  : <object 62>
                 ScamEnv  : [ORBIT_SOCKETDIR=/tmp/orbit-lusth,...]
                ScamArgs  : [scam,scope.s]
             stack-depth  : <builtIn stack-depth()>
                set-cdr!  : <builtIn set-cdr!(spot value)>
                set-car!  : <builtIn set-car!(spot value)>
                     ...

We can see from this output that every environment has five predefined variables. So that they are accessible and available for manipulation with reduced likelihood of being trashed, the first four begin with two underscores. The predefined variables are:

__label
Environments are objects in Scam. The __label field is used to distinguish the native objects from each other. For environments, the label value is environment. Other label values are closure, thunk, error, and exception.
__context
This field holds the enclosing scope. For the outermost scope, the value of this field is nil.
__level
This fields holds the nesting level of dynamic scopes or, in other words, the depth of the call tree for a particular function.
__constructor
This field holds the closure for which the environment was constructed. If the environment did not arise from a function call, the value of this field is nil.
this
A self-reference to the current environment.

As variables are defined, their names and values are inserted into the most local scope at the time of definition.

Nesting scopes

If a definition occurs in a nested begin block, it belongs to the scope in which the begin block is found, recursively. Thus, when the following code is evaluated:

    (define (f w)
        (define x 1)
        (begin
            (define y 2)
            (begin
                (define z 3)
                )
            )
        (ppTable this)
        )
    (f 0)

We see the following output:

    <object 9726>
             __label  : environment
           __context  : <object 9024>
             __level  : 1
       __constructor  : <function f(w)>
                this  : <object 9726>
                   z  : 3
                   y  : 2
                   x  : 1
                   w  : 0

Note that the nested defines of y and z were promoted to the scope of the function body, mirroring the behavior of Python.

To force a block to have its own scope, as in C, C++, and Java, one can use the scope function:

    (define (g w)
        (define x 1)
        (scope
            (define y 2)
            (begin
                (define z 3)
                )
            )
        (ppTable this)
        )
    (g 0)

Now the output reflects that fact that y and z are in their own separate scope:

    <object 9805>
             __label  : environment
           __context  : <object 9024>
             __level  : 1
       __constructor  : <function g(w)>
                this  : <object 9805>
                   x  : 1
                   w  : 0

Because y and z are now in an enclosed scope, they are no longer visible.

lusth@cs.ua.edu


Input and Output Top ObjectsScopes, Environments, and Objects Contents