Publishers of technology books, eBooks, and videos for creative people

Home > Articles

  • Print
  • + Share This
This chapter is from the book

Lexical Scope

Scope delineates the reach of an inferred namespace where you can directly access named identifiers. Scope, in Dart, is delineated by each new set of curly braces. Each set of curly braces acquires its own new scope while inheriting from the scope in which it was declared.

Dart is a lexically scoped language. With lexical scoping, descendant scopes will access the most recently declared variable of the same name. The innermost scope is searched first, followed by a search outward through other enclosing scopes.

{
  //search outermost last
  String name = "Jack Murphy"
  {
    //search innermost first
    print(name)
  }
}

Let’s define a nested function inside main(). Inside the inner() function, declare two variables named level and example. These variables will be available only inside the wrapping scope (Example 4.1).

EXAMPLE 4.1

main() {
  void inner ()
  {
        int level = 1; //not visible in main()
        String example = "scope"; //not visible in main()
        print('example: $example, level: $level');
  }
  inner(); //calls the function which prints - example: scope, level: 1
}

Let’s try to access the variables of example and level outside the inner() function.

EXAMPLE 4.2

main() {
  void inner()
  {
    int level = 1;
    String example = "scope";
    print('example: $example, level: $level');
  }
  inner();
  print('level: $level and example: $example'); //results in an Error
}

In the Dart Analyzer, you’ll see that the print() line in Example 4.2 results in an error: undefined name 'level'. Let’s take a look at how a scope inherits from the scope in which it’s declared and how it searches for named identifiers from inside out.

EXAMPLE 4.3

main() { //a new scope
  String language = "Dart";

  void outer()  {
    //curly bracket opens a child scope with inherited variables

    String level = 'one';
    String example = "scope";

    void inner() { //another child scope with inherited variables
      //the next 'level' variable has priority over previous
      //named variable in the outer scope with the same named identifier
      Map level = {'count': "Two"};
      //prints example: scope, level:two
      print('example: $example, level: $level');
      //inherited from the outermost scope: main
      print('What Language: $language');
    } //end inner scope

    inner();

    //prints example: scope, level:one
    print('example: $example, level: $level');
  } //end outer scope
  outer();
} //end main scope

In Example 4.3, inner() inherits scope from outer(), which inherits scope from main(). This gives inner() access to the outermost scope where the variable language is accessible. Conversely, main() has no idea of the existence of function inner().

To further illustrate lexical scope, let’s take a look at the hashcode property of each variable from within its respective scope.

A hashcode is a value generated by converting each property of an object to a numeric value and then joining those values together to create a single numeric representation of the entire object. Hashcodes are not guaranteed to be the same between runs or on different machines. Objects of differing values or differing types cannot share the same hashcode. Hashcodes give us a uniform approach to compare variables, as shown in Example 4.4.

EXAMPLE 4.4

main() {
  String language = "Dart";
  void outer()  {
    String level = 'one';
    String example = "scope";

    void inner() {
      //declare a new variable named level in memory on the 'inner' scope
      //even though the named identifier is the same as the variable in outer()
      Map level = {'count': "Two"};

      print('-----');
      print('inner::outer.hashcode ' + outer.hashCode.toString());
      print('inner::inner.hashcode ' + outer.hashCode.toString());
      print('inner::language.hashcode ' + language.hashCode.toString());
      print('inner::example.hashcode ' + example.hashCode.toString());
      print('inner::level.hashcode ' + level.hashCode.toString());
    }
    //has access to only outer scope variables
    print('-----');
    print('outer::outer.hashcode ' + outer.hashCode.toString());
    print('outer::inner.hashcode ' + outer.hashCode.toString());
    print('outer::language.hashcode ' + language.hashCode.toString());
    print('outer::example.hashcode ' + example.hashCode.toString());
    print('outer::level.hashcode ' + level.hashCode.toString());
    inner();
  }
  print('-----');
  print('main::language.hashcode ' + language.hashCode.toString());
  print('main::outer.hashcode ' + outer.hashCode.toString());
  print('main::inner.hashcode N/A');

  outer();
}

//Output:
//main::language.hashcode 482586172
//main::outer.hashcode 380883474
//main::inner.hashcode N/A
//-----
//outer::outer.hashcode 380883474
//outer::inner.hashcode 380883474
//outer::language.hashcode 482586172
//outer::example.hashcode 857747343
//outer::level.hashcode 1058535322
//-----
//inner::outer.hashcode 380883474
//inner::inner.hashcode 380883474
//inner::language.hashcode 482586172
//inner::example.hashcode 857747343
//inner::level.hashcode 802594681

Table 4.1 is a matrix of hashcodes for each object from within its respective scopes.

The empty cells in Table 4.1 illustrate that objects that are declared only inside a child scope, such as outer(), are not accessible from parent scopes, such as main().

As you can see in Table 4.1, inner() inherits scope from outer() but also declares its own named identifier of the variable level.

The second declaration of level as a Map does not modify the variable in scope outer(), but instead creates a new variable with its own object reference that’s only accessible within the scope for inner(). After the new level variable is initialized within scope inner(), the hashcode for the variable level inside the scope of inner() reports as 802594681 instead of 1058535322.

Table 4.1 Example Object Hashcode Matrix

OBJECT

SCOPE: main{ }

SCOPE: outer{ }

SCOPE: inner{ }

outer

380883474

380883474

380883474

language

482586172

482586172

482586172

inner

380883474

380883474

level

1058535322

802594681

example

857747343

857747343

  • + Share This
  • 🔖 Save To Your Account