design/16339-alias-decls.md: integrate feedback from tracking issue

- restrict alias declarations to package-qualified (imported) objects
- restrict alias declarations to package level (no function-local aliases)
- mention other uses cases

For golang/go#16339.

Change-Id: I1047dba0c395f50297d7a920e02a1ba21ac71844
Reviewed-on: https://go-review.googlesource.com/25032
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
diff --git a/design/16339-alias-decls.md b/design/16339-alias-decls.md
index a4aef7c..8e29ee7 100644
--- a/design/16339-alias-decls.md
+++ b/design/16339-alias-decls.md
@@ -1,15 +1,21 @@
 # Proposal: Alias declarations for Go
 
 Authors: Robert Griesemer & Rob Pike.
-Last updated: June 31, 2016
+Last updated: July 18, 2016
 
 Discussion at https://golang.org/issue/16339.
 
 ## Abstract
 We propose to add alias declarations to the Go language. An alias declaration
 introduces an alternative name for an object (type, function, etc.) declared
-elsewhere. Aliases simplify splitting up packages because clients can be
-updated incrementally, which is crucial for large-scale refactoring.
+elsewhere. Alias declarations simplify splitting up packages because clients
+can be updated incrementally, which is crucial for large-scale refactoring.
+They also facilitate multi-package "components" where a top-level package
+is used to provide a component's public API with aliases referring to the
+componenent's internal packages. Alias declarations are
+important for the Go implementation of the "import public" feature of Google
+protocol buffers. They also provide a more fine-grained and explicit
+alternative to "dot-imports".
 
 ## 1. Motivation
 Suppose we have a library package L and a client package C that depends on L.
@@ -99,7 +105,7 @@
 To address these issues with a single, unified mechanism, we propose a new
 form of declaration in Go, called an alias declaration. As the name suggests,
 an alias declaration introduces an alternative name for a given object that
-has been declared elsewhere, possibly in a different package.
+has been declared elsewhere, in a different package.
 
 An alias declaration in package L makes it possible to move the original
 declaration of an object X (a constant, type, variable, or function) from
@@ -108,9 +114,7 @@
 
 Note that the two predeclared types byte and rune are aliases for the
 predeclared types uint8 and int32. Alias declarations will enable users
-to define their own aliases, and byte and rune can then be defined
-internally using this general language mechanism rather than rely on
-built-in “magic” only available to the implementation.
+to define their own aliases, similar to byte and rune.
 
 ## 3. Notation
 The existing declaration syntax for constants effectively permits
@@ -135,56 +139,61 @@
 var V = L1.V  // V is initialized to L1.V
 ```
 
-Instead of "=" we propose the new alias operator  "->"  to solve the
+Instead of "=" we propose the new alias operator "=>" to solve the
 syntactic issue:
 
 ```
-const C -> L1.C  // for regularity only, same effect as const C = L1.C
-type  T -> L1.T  // T is an alias for type L1.T
-var   V -> L1.V  // V is an alias for variable L1.V
-func  F -> L1.F  // F is an alias for function L1.F
+const C => L1.C  // for regularity only, same effect as const C = L1.C
+type  T => L1.T  // T is an alias for type L1.T
+var   V => L1.V  // V is an alias for variable L1.V
+func  F => L1.F  // F is an alias for function L1.F
 ```
 
 With that, a general alias specification is of the form:
 
-AliasSpec = identifier "->" [ PackageName "." ] identifier .
+AliasSpec = identifier "=>" PackageName "." identifier .
 
-An alias declaration may refer to another alias, as in:
+Per the discussion at https://golang.org/issue/16339, and based on feedback
+from adonovan@golang, to avoid abuse, alias declarations may refer to imported
+and package-qualified objects only (no aliases to local objects or
+"dot-imports").
+Furthermore, they are only permitted at the top (package) level,
+not inside a function.
 
-```
-type T1 -> L1.T  // T1 is an alias for L1.T
-type T2 -> T1    // T2 is an alias for L1.T
-```
+These restriction do not hamper the utility of aliases for the intended
+use cases. Both restrictions can be trivially lifted later if so desired;
+we start with them out of an abundance of caution.
 
-The lhs identifier (T1, T2 in the example above) in an alias declaration is
-called the alias name (or alias for short). For each alias name there is an
-original name (or original for short), which is the non-alias name declared
-for a given object (here L1.T).
+An alias declaration may refer to another alias.
+
+The LHS identifier (C, T, V, and F in the examples above) in an alias
+declaration is called the _alias name_ (or _alias_ for short). For each alias
+name there is an _original name_ (or _original_ for short), which is the
+non-alias name declared for a given object (e.g., L1.T in the example above).
 
 Some more examples:
 
 ```
-import "math"
 import "oldp"
 
-var v -> oldp.V  // local alias, not exported
+var v => oldp.V  // local alias, not exported
 
+// alias declarations may be grouped
 type (
-	T1 -> oldp.T1  // original for T1 is oldp.T1
-	T2 -> T1       // original for T2 is oldp.T1
+	T1 => oldp.T1  // original for T1 is oldp.T1
+	T2 => oldp.T2  // original for T2 is oldp.T2
+	T3    [8]byte  // regular declaration may be grouped with aliases
 )
 
-var (
-	V1 -> oldp.V1
-	V2 T2  // same effect as: var V2 oldp.T1
-)
+var V2 T2  // same effect as: var V2 oldp.T2
 
-func myF -> oldp.F  // local alias, not exported
-func G   -> oldp.G
+func myF => oldp.F  // local alias, not exported
+func G   => oldp.G
+
+type T => oldp.MuchTooLongATypeName
 
 func f() {
-	type T -> muchTooLongATypeName
-	x := T{}  // same effect as: x := muchTooLongATypeName{}
+	x := T{}  // same effect as: x := oldp.MuchTooLongATypeName{}
 	...
 }
 ```
@@ -198,18 +207,24 @@
 The short variable declaration form (using ":=") cannot be used to
 declare an alias.
 
-Discussion: Introducing a new operator ("->") has the advantage of not
+Discussion: Introducing a new operator ("=>") has the advantage of not
 needing to introduce a new keyword (such as "alias"), which we can't really
 do without violating the Go 1 promise (though r@golang and rsc@golang observe
 that it would be possible to recognize "alias" as a keyword at the package-
 level only, when in const/type/var/func position, and as an identifier
-otherwise, and probably not break existing code). As proposed, it also means
-that an alias declaration must specify what kind of object the alias refers
-to (const, type, var, or func), which we think is an advantage: It makes it
-clear to a user what the alias denotes (as with existing declarations); and
-it also makes it possible to report an error at the type of the alias
-declaration if the aliased object changes (e.g., from being a constant to a
-variable) rather than only at where the alias is used.
+otherwise, and probably not break existing code).
+
+The token sequence "=" ">" (or "==" ">") is not a valid sequence in a Go
+program since ">" is a binary operator that must be surrounded by operands,
+and the left operand cannot end in "=" or "==". Thus, it is safe to introduce
+"=>" as a new token sequence without invalidating existing programs.
+
+As proposed, an alias declaration must specify what kind of object the alias
+refers to (const, type, var, or func). We believe this is an advantage:
+It makes it clear to a user what the alias denotes (as with existing
+declarations). It also makes it possible to report an error at the location
+of the alias declaration if the aliased object changes (e.g., from being a
+constant to a variable) rather than only at where the alias is used.
 
 On the other hand, mdempsky@golang points out that using a keyword would
 permit making changes in a package L1, say change a function F into a type F,
@@ -248,76 +263,58 @@
 file scope: the same alias may have to be imported in multiple files of the
 same package, possibly with different names.)
 
-The choice of symbol ("->") is somewhat arbitrary, but both "A -> B" and
-"A => B" conjure up the image of a reference or forwarding from A to B.
-Furthermore, "->" is also used in Unix directory listings for symbolic links,
-where the lhs is another name (an alias) for the file mentioned on the rhs.
+The choice of token ("=>") is somewhat arbitrary, but both "A => B" and
+"A -> B" conjure up the image of a reference or forwarding from A to B.
+The token "->" is also used in Unix directory listings for symbolic links,
+where the lhs is another name (an alias) for the file mentioned on the RHS.
 
 dneil@golang and r@golang observe that if "->" is written "in reverse" by
 mistake, a declaration "var X -> p.X" meant to be an alias declaration is
 close to a regular variable declaration "var X <-p.X" (with a missing "=");
 though it wouldn’t compile.
 
-adonovan@golang points out that we could permit aliases only to imported
-(explicitly package-qualified or dot-imported) identifiers to start with.
-This would solve the immediate problem at hand and still allow the more
-general form eventually. It may also mean less work during declaration cycle
-detection.
+Many people expressed a preference for "=>" over "->" on the tracking issue.
+The argument is that "->" is more easily confused with a channel operation.
+A few people would like to use "@" (as in _@lias_). For now we proceed with
+"=>" - the token is trivially changed down the road if there is strong general
+sentiment or a convincing argument for any other notation.
 
 ## 3. Semantics and rules
 An alias declaration declares an alternative name, the alias, for a constant,
-type, variable, or function, referred to by the rhs of the alias declaration.
-The rhs must be a (possibly package-qualified) identifier; it may itself be an
-alias, or it may the original name for the aliased object.
+type, variable, or function, referred to by the RHS of the alias declaration.
+The RHS must be a package-qualified identifier; it may itself be an alias, or
+it may be the original name for the aliased object.
+
+Alias cycles are impossible by construction since aliases must refer to fully
+package-qualified (imported) objects and package import cycles are not
+permitted.
 
 An alias denotes the aliased object, and the effect of using an alias is
-indistinguishable from the effect of using the original; the only difference
-is the name.
+indistinguishable from the effect of using the original; the only visible
+difference is the name.
+
+An alias declaration may only appear at the top- (package-) level where it
+is valid to have a keyword-based constant, type, variable, or function
+declaration. Alias declarations may be grouped.
 
 The same scope and export rules (capitalization for export) apply as for all
-other identifiers.
+other identifiers at the top-level.
 
-An alias declaration may be used wherever it is valid to have a keyword-based
-constant, type, variable, or function declaration. In particular, alias
-declarations may be grouped and aliases may refer to locally declared objects.
+The scope of an alias identifier at the top-level is the package block
+(as is the case for an identifier denoting a constant, type, variable,
+or function).
 
-The scope of an alias identifier at the top-level (outside any function) is
-the package block (as is the case now for an identifier denoting a constant,
-type, variable, or function). The scope of an alias identifier inside a
-function begins at the end of the alias specification and ends at the end of
-the innermost block (analogous to what is the case now for local declarations).
+An alias declaration may refer to unsafe.Pointer, but not to any of the unsafe
+functions.
 
-An alias declaration may refer to any predeclared type including
-unsafe.Pointer, but not to any other predeclared object in the Universe scope
-(true, false, nil, iota, or any of the predeclared functions) nor any function
-of package unsafe (unsafe.Alignof, unsafe.Offsetof, unsafe.Sizeof).
+A package is considered "used" if any imported object of a package is used.
+Consequently, declaring an alias referring to an object of an package marks
+the package as used.
 
-An alias may refer to another alias, but cycles are forbidden. The existing
-lexical rules for cycle detection will serve for aliases as well.
-
-A variable “used” via an alias is considered “used” as if it were accessed by
-its original name.
-
-Discussion: The main reason for permitting aliases to predeclared types is
-regularity - we already implement byte and rune type aliases and the
-mechanisms for it exist already. There is no inherent difficulty in permitting
-aliases for the predeclared values nil, true, and false. However, due to the
-special meaning of nil it seems unwise to permit aliases to nil. The same is
-true for iota. The values true and false are constants, so aliases (as unwise
-as they may be) are already possible with constant declarations. Predeclared
-functions such as new or append (and others) are not regular functions; new
-takes a type argument, and append has a generic signature. These function
-types cannot be expressed via ordinary function signatures. If an alias to
-such a function were exported it would require a new mechanism to export these
-functions. Extra machinery for a questionable use case does not seem
-justifiable.
-
-For purposes of implementation, unsafe.Pointer and the functions in package
-unsafe are treated like any of the other predeclared objects. It is already
-possible to declare a new type P with unsafe.Pointer as its underlying type,
-export P, and then use that P in another package to convert any pointer type
-to P, which then further can be converted to an uintptr. Thus restricting
-aliases in some way for unsafe.Pointer is not a meaningful restriction.
+Discussion: The original proposal permitted aliases to any (even local)
+objects and also to predeclared types in the Universe scope. Furthermore,
+it permitted alias declarations inside functions. See the tracking issue
+and earlier versions of this document for a more detailed discussion.
 
 ## 4. Impact on other libraries and tools
 Alias declarations are a source-level and compile-time feature, with no
@@ -384,6 +381,23 @@
 
 To be prototyped.
 
+## 6. Other use cases
+Alias declarations facilitate the construction of larger-scale libraries or
+"components". For organizational and size reasons it often makes sense to split
+up a large library into several sub-packages. The exported API of a sub-package
+is driven by internal requirements of the component and may be only remotely
+related to its public API. Alias declarations make it possible to "pull out"
+the relevant declarations from the various sub-packages and collect them in
+a single top-level package that represents the component's API.
+The other packages can be organized in an "internal" sub-directory,
+which makes them virtually inaccessible through the `go build` command (they
+cannot be imported).
+
+TODO(gri): Expand on use of alias declarations for protocol buffer's
+"import public" feature.
+
+TODO(gri): Expand on use of alias declarations instead of "dot-imports".
+
 # Appendix
 
 ## A1. Syntax changes
@@ -391,7 +405,7 @@
 and concentrated. There is a new declaration specification called AliasSpec:
 
 ```
-AliasSpec = identifier "->" [ PackageName "." ] identifier .
+AliasSpec = identifier "=>" PackageName "." identifier .
 ```
 
 An AliasSpec binds an identifier, the alias name, to the object (constant,