User Tools

Site Tools


Sidebar

Jump to
AmbientTalk
CRIME
iScheme

at:tutorial:multiparadigm

This is an old revision of the document!


On Scoping, Closures, Methods and Messages

This tutorial chapter is still under construction

This tutorial chapter goes into a bit more detail on the subtle interplay between AmbientTalk's functional aspects (e.g. block closures, higher-order functions and lexical scoping) and its object-oriented aspects (e.g. objects and delegation). It is also described how methods and messages can be manipulated as first-class objects in their own right.

Lexical Scope vs Object Scope

AmbientTalk distinguishes between two kinds of scopes:

  1. the lexical scope, which is the set of all variables that are lexically visible in the program text. In other words: all variables in an enclosing scope are part of the lexical scope of the enclosed (nested) scope.
  2. the object scope, which is delimited by a chain of delegating objects. When sending a message to an object, the object and its parent objects delimit the scope in which the message is looked up.

The rules for distinguishing which scope to use when resolving an identifier are straightforward:

  1. Unqualified access to a variable, e.g. x, is always resolved in the lexical scope.
  2. Qualified access to a variable, e.g. o.x, is always resolved in the receiver's object scope.

These rules also hold for method invocation: the invocation f() is resolved lexically: f is looked up in the lexical scope; the invocation o.m() is resolved dynamically, i.e. m is looked up in o. These rules have a large effect on programs: lexical variable access can be statically determined, while qualified access is subject to late binding (enabling object-oriented polymorphism). As a programmer, you must be aware of the fundamental difference in semantics.

Probably the most important conseqence of these rules is that great care has to be taken when an object accesses its own fields or methods. It can now do so in two ways. For example:

def o := object: {
  def x := 5;
  def getStatic() { x };
  def getDynamic() { self.x };
}

In the code snippet above, o defines two accessors for its field x. The getStatic accessor refers to x unqualified. As a result, x is looked up in the lexical scope and found in o. The getDynamic accessor accesses the field by means of a self-send. According to the rules outlined above, x is accessed in a qualified way, which means it is looked up in the object scope of o. Now consider the following code:

def o2 := extend: o with: {
  def x := 6;
}

This program behaves as follows:

>o.getStatic()
>> 5
>o.getDynamic()
>> 5
>o2.getStatic()
>> 5
>o2.getDynamic()
>> 6

Nesting Objects

Methods vs Closures

External Methods

First-class Methods

First-class Messages

at/tutorial/multiparadigm.1182244877.txt.gz · Last modified: 2007/06/19 11:33 (external edit)