summaryrefslogtreecommitdiff
path: root/04-identifiers-names-and-scopes.md
blob: 1266fce2f6729f57095932d487de1a449ff81ab8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
Identifiers, Names and Scopes
=============================

Names in Scala identify types, values, methods, and classes which are
collectively called _entities_. Names are introduced by local
[definitions and declarations](#basic-declarations-and-definitions), 
[inheritance](#class-members),
[import clauses](#import-clauses), or 
[package clauses](#packagings)
which are collectively called _bindings_.

Bindings of different kinds have a precedence defined on them:

#. Definitions and declarations that are local, inherited, or made 
   available by a package clause in the same compilation unit where the 
   definition occurs have highest precedence. 
#. Explicit imports have next highest precedence.
#. Wildcard imports  have next highest precedence.
#. Definitions made available by a package clause not in the 
   compilation unit where the definition occurs have lowest precedence.


There are two different name spaces, one for [types](#types)
and one for [terms](#expressions). The same name may designate a
type and a term, depending on the context where the name is used.

A binding has a _scope_ in which the entity defined by a single
name can be accessed using a simple name. Scopes are nested.  A binding
in some inner scope _shadows_ bindings of lower precedence in the
same scope as well as bindings of the same or lower precedence in outer
scopes. 

Note that shadowing is only a partial order. In a situation like

~~~~~~~~~~~~~~ {.scala}
val x = 1;
{ import p.x; 
  x }
~~~~~~~~~~~~~~

neither binding of `x` shadows the other. Consequently, the
reference to `x` in the third line above would be ambiguous.

A reference to an unqualified (type- or term-) identifier $x$ is bound
by the unique binding, which

- defines an entity with name $x$ in the same namespace as the identifier, and
- shadows all other bindings that define entities with name $x$ in that 
  namespace.

It is an error if no such binding exists.  If $x$ is bound by an
import clause, then the simple name $x$ is taken to be equivalent to
the qualified name to which $x$ is mapped by the import clause. If $x$
is bound by a definition or declaration, then $x$ refers to the entity
introduced by that binding. In that case, the type of $x$ is the type
of the referenced entity.

(@) Assume the following two definitions of a objects named 
`X` in packages `P` and `Q`.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.scala}
    package P {
      object X { val x = 1; val y = 2 }
    }

    package Q {
      object X { val x = true; val y = "" }
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    The following program illustrates different kinds of bindings and
    precedences between them.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.scala}
    package P {                  // `X' bound by package clause
    import Console._             // `println' bound by wildcard import
    object A {                   
      println("L4: "+X)          // `X' refers to `P.X' here
      object B {
        import Q._               // `X' bound by wildcard import
        println("L7: "+X)        // `X' refers to `Q.X' here
        import X._               // `x' and `y' bound by wildcard import
        println("L8: "+x)        // `x' refers to `Q.X.x' here
        object C {
          val x = 3              // `x' bound by local definition
          println("L12: "+x)     // `x' refers to constant `3' here
          { import Q.X._         // `x' and `y' bound by wildcard import
    //      println("L14: "+x)   // reference to `x' is ambiguous here
            import X.y           // `y' bound by explicit import
            println("L16: "+y)   // `y' refers to `Q.X.y' here
            { val x = "abc"      // `x' bound by local definition
              import P.X._       // `x' and `y' bound by wildcard import
    //        println("L19: "+y) // reference to `y' is ambiguous here
              println("L20: "+x) // `x' refers to string ``abc'' here
    }}}}}}
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A reference to a qualified (type- or term-) identifier $e.x$ refers to
the member of the type $T$ of $e$ which has the name $x$ in the same
namespace as the identifier. It is an error if $T$ is not a 
[value type](#value-types). The type of $e.x$ is the member type of the
referenced entity in $T$.