CSC447

Concepts of Programming Languages

Scope

Instructor: James Riely

Scope

  • Scope of an identifier
    • region of text in which it may be used

Common Scope Rules

  • z is in scope after its declaration until end of if

void f (int x) {
  int y = x + 1;
  if (x > y) {
    int z = y + 1;
    printf ("z = %d\n", z);
  }
}
          

Terminology: Occurrences

  • Occurrences of identifiers classified as one of
    • free occurrence has no matching binding
      
      y = 5*x;   // Free occurrences of x and y
                        
    • binding occurrence declares the identifier
      
      int y;    // binding occurrence of y
                        
    • bound occurrence follows matching declaration
      
      int y;    // Binding occurrence of y
      int x;    // Binding occurrence of x
      
      x=6;      // Bound occurrence of x
      y = 5*x;  // Bound occurrences of x and y
                        

Terminology: Occurrences

  • Complete programs usually have no free occurrences of identifiers
  • How do IDEs treat free occurrences?

Not Just Variables

  • Applies to identifiers for
    • normal variables
    • function parameters
    • function type parameters
    • function/method names
    • class names
    • and more

Forward Declarations

  • C, C++ require forward declarations
  • Most other modern languages do not

char f (int x);

char g (int x) {
  return f (x) + f (x);
}

char f (int x) {
  if (x > 0) { 
    return g (x >> 8);
  } else {
    return 1;
  }
}
          

Shadowing - Java


public class C {
  static void f () {
    int x = 1;
    {
      int y = x + 1;
      {
        int x = y + 1;
        System.out.println ("x = " + x);
      }
    }
  }
}
          

$ javac C.java 
C.java:7: error: variable x is already defined in method f()
        int x = y + 1;
            ^
1 error
          

Shadowing - Java

  • Fields have different treatment

public class C {
  static int x = 1;
  static void f () {
    int y = x + 1;
    {
      int x = y + 1;
      System.out.println ("x = " + x);
    }
  }
  public static void main (String[] args) {
    f ();
  }
}
          

$ javac C.java 
$ java C
x = 3
          

Shadowing C

  • C is less strict than Java (on shadowing)

int main () {
  int x = 1;
  {
    int y = x + 1;
    {
      int x = y + 1;
      printf ("x = %d\n", x);
    }
  }
}
          

$ gcc -o scope scope.c 
$ ./scope
x = 3
          

Shadowing Scala

  • Scala is less strict than Java (on shadowing)
  • Indentation is significant here

object C:
  def f () = 
    var x = 1; 
      var y = x + 1; 
        var x = y + 1; 
        println ("x = " + x) 
  def main (args:Array[String]) =  
    f () 
          
 
$ scalac C.scala  
$ scala C 
x = 3 
          

Shadowing Scala

  • Shadowing occurs in the REPL naturally
 
scala> val x = 1 
x: Int = 1 

scala> def f (a:Int) = x + a 
f: (a: Int)Int 

scala> f (10) 
res0: Int = 11 

scala> val x = 2 
x: Int = 2 

scala> x 
res1: Int = 2 

scala> f (10) 
res2: Int = 11 
          

Shadowing Scala

  • REPL behavior corresponds to
 
{ 
  val x = 1; 
  def f (a:Int) = x + a 
  f (10) 
  { 
    val x = 2;  
    x 
    f (10) 
    ... 
  } 
} 
          

Shadowing and Recursion in C

  • Is x in scope?

int main (void) {
  int x = 10;
  {
    int x = x + 1;
    printf ("x = %08x\n", x);
  }
  return 0;
}
          

$ gcc -o scope scope.c

$ gcc -Wall -o scope scope.c
scope.c: In function ‘main’:
scope.c:5:7: warning: unused variable ‘x’ [-Wunused-variable]
scope.c:7:9: warning: ‘x’ is used uninitialized in this function [-Wuninitialized]

$ ./scope 
x = 00000001
          

Shadowing and Recursion in Scala

  • Is x in scope?

val y = 1
def g() = { val x:Int = y + 1; x }
val x = 1
def f() = { val x:Int = x + 1; x }
          

|def f() = { val x:Int = x + 1; x }
|                        ^
|               x is a forward reference extending over the definition of x