Back Contents Next

7. Scoping

Scoping is the issue of where an entity name may be accessed from and how it is determined which entity a name refers to. A scope is a space in which names reside and one is created for every object. In effect the scope is delineated by the curly braces of the object body. When an object is instantiated from a pattern it has its own scope which includes the pattern parameters and contains all the members of the object as described by the pattern body.

7.1 Lexical Containment

The previous discussion referred to the next lexically enclosing scope. A lexically enclosing scope is one which contains the given entity or statement textually. That is, the lexically containing scope is the object in which its definition is written. So if an object is defined in one scope but assigned to a name in another, its lexically containing scope is the first one. Objects instantiated from patterns are lexically contained by the object containing the pattern declaration. Objects contained within a pattern are lexically contained by the particular instantiation they were created in

7.2 Access Modifiers

Any entity may be preceded by an access modifier. An access modifier is a keyword designating which objects will have access to the member. There are five access modifiers. They are 'public', 'scope', 'protected', 'private', and 'personal'. If a member is not preceded by an access modifier it defaults to being personal. If accessing a member of a member of a member of an object etc. one must have the access to select each member in each object. So a public member may not be accessible if it is in a private object. Entities are always accessible in the scope lexically containing them. If a member is accessible in a scope then it is accessible in any lexically contained scope no matter the access modifier applied.

When overriding patterns the overriding pattern must have the same or more open access than the overridden pattern. When an entity is accessible to a scope which is defined by a pattern it is generally accessible to all objects instantiated from that pattern (personal is the exception to this).

7.2.1 Public

The 'public' keyword indicates that the entity may be accessed from any object.

7.2.2 Scope

The access modifier 'scope' is the most flexible and powerful of the access modifiers. It allows one to provide arguments exactly specifying in what objects the member is accessible. The names of the objects or patterns in which the member may be accessed are given after the scope keywords in parentheses and separated by commas as:

public animal
{
    public fish
    {
    }

    public bird
    {
    }

    public worm
    {
        scope(fish, bird) food
        {
        }
    }
}

In this example the worm.food is accessible to both the fish and bird but not to the animal. Note that this is a type of access which could not be specified with any of the other modifiers. If a pattern name were listed then it would be accessible to any object created from that pattern. This use of scope introduces coupling and like the friend's mechanism in C++ its use is discouraged.

In addition to directly specifying the scopes in which the name is visible it is possible to allow the scope access modifier to default to a reasonable value. This feature is not fundamental, one could just as easily always specify the desired scope. This is done by omitting the parameters to scope along with the parentheses. In this case it has the same meaning as Java's package or friendly access which is signified by no access modifier.

public home
{
    public Dog : Animal
    {
        scope bark() -> void
        {
        }
    }
}

To be more precise the entity is accessible in the most tightly enclosing module (see 11.1 Modules). This is the only instance in which modules are distinguished from other objects. In the above example the bark method of dog would be accessible from the home module but not modules that contain home.

7.2.3 Protected

A 'protected' entity may be accessed only from within the current scope (and other objects of the same type if the current scope is defined by a pattern) and in any subclasses. It is possible to increase the access to public by overriding a protected pattern.

7.2.4 Private

A 'private' member, is accessible to all objects of the same type. Private has little use in an object body because their are no instances of same type.

7.2.5 Personal

A 'personal' member may be accessed from only within the scope that encloses it. This is tighter access than private since other objects of the same type can't access it. When an access modifier is omitted personal is the default. Pattern parameters are personal when not preceded by another modifier.

7.3 Name Lookup

When an unqualified name appears in an expression then the rules of scoping are used to determine which object it refers to. An unqualified name is one which is not preceded by a member selection operator. In this case a series of scopes is searched for that name. The search begins in the current scope, the scope containing the expression. If the name is defined and accessible in that scope before the expression occurs then the search is terminated. Remember that names declared in super and interface types are part of the current scope (they are just declared before anything in this scope). Otherwise the search is continued in the next scope lexically containing the current scope. This process continues with the new scope as the current scope. It may terminate when the outer most scope is found to not contain the name (i.e. the one containing all stand alone entities). In which case it is an error. The process may also change if the current scope was created from a pattern. If the current scope is created from a pattern and it is necessary to search outside that scope then not just the part of the scope before the expression is searched but instead the whole scope is searched. Once this transition is made, the whole scopes will be searched all the way out to the top level.

Note that a pattern and object with the same name contained in the same scope are consider to be closely coupled scopes since they have the same name and are indistinguishable. Thus each has private access to the other. That is the object has private access to all the instances and all the instances have private access to the object. In fact the object's properties are automatically in scope declared before any name in the instance but after any name in the super class.

When a scope is found which contains a name, then the name is taken to refer to that entity. If multiple accessible entities exists in that scope with the given name then the name is overloaded and will need to be further resolved. If names before the expression is all that is being searched then only these names are taken into account. The name may be further resolved as indicated by the expression containing it (see 6.1.1 Names).

7.4 Pseudonyms

In addition to the normal name resolution rules their are four object pseudonyms. These are special names which can be used in different scopes to refer to related objects whether or not they are named. They need not appear as an unqualified name.

7.4.1 Self Keyword

The keyword 'self' may be used to refer to the current object. When used in an object body it refers to the object of which this is the body. When used in a pattern it refers to the object created from that pattern (which is where it is evaluated). It is not possible to assign a new value to self. Self is defined as being personal, so it can't be accessed from outside the object's scope. Self is also used as a special return type (see 4.2.2 Returning Self).

7.4.2 This Keyword

The keyword 'this' correspond to what programmers from a background in C++ or Java would expect. The object referred to by this depends on where the keyword is used. It has the following meanings, when used in:

The last case is the most complex as it can lead to a repeat of the application of the rules to the object of which self is lexically contained in. This is defined as being a personal property.

7.4.3 Super Keyword

The keyword 'super' refers to the object that is the super type of the current object. That is all those parts of the current object which are defined in the super class, including those parts that may be hidden by overriding. There is no other way to refer to this object. The super keyword may be used to invoke the original version of an overridden pattern. It is also used to call the super types creation code (see 5.2 Super Type). Super is a personal property.

7.4.4 Outer Keyword

The final pseudonym is outer. The outer keyword may be used as a personal property of any object. When accessed from an explicitly declared object (as object.outer) it refers to the object lexically containing the one whose outer property is being accessed. When used without qualifying which object it refers to it is assumed that the object being referred to is this (as 'this.outer').



Back Contents Next

jwalker@cs.oberlin.edu