]> Cypherpunks repositories - gostls13.git/commitdiff
spec: type assertions and type switches must be valid
authorRobert Griesemer <gri@golang.org>
Thu, 6 Dec 2012 17:17:20 +0000 (09:17 -0800)
committerRobert Griesemer <gri@golang.org>
Thu, 6 Dec 2012 17:17:20 +0000 (09:17 -0800)
The spec didn't preclude invalid type assertions and
type switches, i.e., cases where a concrete type doesn't
implement the interface type in the assertion in the first
place. Both, the gc and gccgo compiler exclude these cases.
This is documenting the status quo.

Also:
- minor clean up of respective examples
- added sentence about default case in select statements

Fixes #4472.

R=rsc, iant, r, ken
CC=golang-dev
https://golang.org/cl/6869050

doc/go_spec.html

index 4061c780fb0ef97baecefbe9e861ee971be23958..f58c3232168ff7b307caed00346fbb45a2d36af2 100644 (file)
@@ -1,6 +1,6 @@
 <!--{
        "Title": "The Go Programming Language Specification",
-       "Subtitle": "Version of December 4, 2012",
+       "Subtitle": "Version of December 6, 2012",
        "Path": "/ref/spec"
 }-->
 
@@ -2668,8 +2668,11 @@ The notation <code>x.(T)</code> is called a <i>type assertion</i>.
 More precisely, if <code>T</code> is not an interface type, <code>x.(T)</code> asserts
 that the dynamic type of <code>x</code> is <a href="#Type_identity">identical</a>
 to the type <code>T</code>.
+In this case, <code>T</code> must <a href="#Method_sets">implement</a> the (interface) type of <code>x</code>;
+otherwise the type assertion is invalid since it is not possible for <code>x</code>
+to store a value of type <code>T</code>.
 If <code>T</code> is an interface type, <code>x.(T)</code> asserts that the dynamic type
-of <code>x</code> implements the interface <code>T</code> (§<a href="#Interface_types">Interface types</a>).
+of <code>x</code> implements the interface <code>T</code>.
 </p>
 <p>
 If the type assertion holds, the value of the expression is the value
@@ -2679,8 +2682,19 @@ In other words, even though the dynamic type of <code>x</code>
 is known only at run time, the type of <code>x.(T)</code> is
 known to be <code>T</code> in a correct program.
 </p>
+
+<pre>
+var x interface{} = 7  // x has dynamic type int and value 7
+i := x.(int)           // i has type int and value 7
+
+type I interface { m() }
+var y I
+s := y.(string)        // illegal: string does not implement I (missing method m)
+r := y.(io.Reader)     // r has type io.Reader and y must implement both I and io.Reader
+</pre>
+
 <p>
-If a type assertion is used in an assignment or initialization of the form
+If a type assertion is used in an <a href="#Assignments">assignment</a> or initialization of the form
 </p>
 
 <pre>
@@ -2696,7 +2710,7 @@ otherwise, the expression returns <code>(Z, false)</code> where <code>Z</code>
 is the <a href="#The_zero_value">zero value</a> for type <code>T</code>.
 No run-time panic occurs in this case.
 The type assertion in this construct thus acts like a function call
-returning a value and a boolean indicating success.  (§<a href="#Assignments">Assignments</a>)
+returning a value and a boolean indicating success.
 </p>
 
 
@@ -4159,9 +4173,20 @@ case x == 4: f3()
 A type switch compares types rather than values. It is otherwise similar
 to an expression switch. It is marked by a special switch expression that
 has the form of a <a href="#Type_assertions">type assertion</a>
-using the reserved word <code>type</code> rather than an actual type.
-Cases then match literal types against the dynamic type of the expression
-in the type assertion.
+using the reserved word <code>type</code> rather than an actual type:
+</p>
+
+<pre>
+switch x.(type) {
+// cases
+}
+</pre>
+
+<p>
+Cases then match actual types <code>T</code> against the dynamic type of the
+expression <code>x</code>. As with type assertions, <code>x</code> must be of
+<a href="#Interface_types">interface type</a>, and each non-interface type
+<code>T</code> listed in a case must implement the type of <code>x</code>.
 </p>
 
 <pre class="ebnf">
@@ -4197,17 +4222,17 @@ the following type switch:
 <pre>
 switch i := x.(type) {
 case nil:
-       printString("x is nil")
+       printString("x is nil")                // type of i is type of x (interface{})
 case int:
-       printInt(i)  // i is an int
+       printInt(i)                            // type of i is int
 case float64:
-       printFloat64(i)  // i is a float64
+       printFloat64(i)                        // type of i is float64
 case func(int) float64:
-       printFunction(i)  // i is a function
+       printFunction(i)                       // type of i is func(int) float64
 case bool, string:
-       printString("type is bool or string")  // i is an interface{}
+       printString("type is bool or string")  // type of i is type of x (interface{})
 default:
-       printString("don't know the type")
+       printString("don't know the type")     // type of i is type of x (interface{})
 }
 </pre>
 
@@ -4218,22 +4243,23 @@ could be rewritten:
 <pre>
 v := x  // x is evaluated exactly once
 if v == nil {
+       i := v                                 // type of i is type of x (interface{})
        printString("x is nil")
 } else if i, isInt := v.(int); isInt {
-       printInt(i)  // i is an int
+       printInt(i)                            // type of i is int
 } else if i, isFloat64 := v.(float64); isFloat64 {
-       printFloat64(i)  // i is a float64
+       printFloat64(i)                        // type of i is float64
 } else if i, isFunc := v.(func(int) float64); isFunc {
-       printFunction(i)  // i is a function
+       printFunction(i)                       // type of i is func(int) float64
 } else {
-       i1, isBool := v.(bool)
-       i2, isString := v.(string)
+       _, isBool := v.(bool)
+       _, isString := v.(string)
        if isBool || isString {
-               i := v
-               printString("type is bool or string")  // i is an interface{}
+               i := v                         // type of i is type of x (interface{})
+               printString("type is bool or string")
        } else {
-               i := v
-               printString("don't know the type")  // i is an interface{}
+               i := v                         // type of i is type of x (interface{})
+               printString("don't know the type")
        }
 }
 </pre>
@@ -4501,7 +4527,8 @@ If any of the resulting operations can proceed, one of those is
 chosen and the corresponding communication and statements are
 evaluated.  Otherwise, if there is a default case, that executes;
 if there is no default case, the statement blocks until one of the communications can
-complete.
+complete. There can be at most one default case and it may appear anywhere in the
+"select" statement.
 If there are no cases with non-<code>nil</code> channels,
 the statement blocks forever.
 Even if the statement blocks,