Skip to content

Instantly share code, notes, and snippets.

@mtilson
Last active March 18, 2020 19:51
Show Gist options
  • Save mtilson/4536e69d8d667823d58c78d9687e8b09 to your computer and use it in GitHub Desktop.
Save mtilson/4536e69d8d667823d58c78d9687e8b09 to your computer and use it in GitHub Desktop.
how type assertions rules are applied [golang]
// https://play.golang.org/p/SMdNNFLp3OJ
// See https://golang.org/ref/spec#Type_assertions for the notation of type assertion `x.(T)` and `x.(*T)`.
// Here we use:
// for `T`, `*T`:
// - `ConcreteTypeTypeReceiver` if T is concrete type (not an interface type) with Type Method Receiver
// - `ConcreteTypeTypeReceiver` satisfies `InterfaceType` interface
// - `*ConcreteTypeTypeReceiver` if *T is concrete type (not an interface type) with Type Method Receiver
// - `*ConcreteTypeTypeReceiver` satisfies `InterfaceType` interface
// - `*ConcreteTypePtrReceiver` if *T is concrete type (not an interface type) with Pointer Method Receiver
// - `*ConcreteTypePtrReceiver` satisfies `InterfaceType` interface
// - `InterfaceType` if T is interface type
// for `x`:
// - `InterfaceType` - defined interface type we use as interface value for type assertions
// - `interface{}` - empty interface we use as interface value for type assertions
package main
import "fmt"
type ConcreteTypeTypeReceiver struct {n int}
func (c ConcreteTypeTypeReceiver) someMethod() int {return c.n}
// declaration above SUPPORTs the following types
// 1. `ConcreteTypeTypeReceiver` - with methods (according to case C2)
// 1. `someMethod() int`
// 2. `*ConcreteTypeTypeReceiver` - with methods (according to case F2)
// 1. `someMethod() int`
type ConcreteTypePtrReceiver struct {n int}
func (c *ConcreteTypePtrReceiver) someMethod() int {return c.n}
// declaration above DOS NOT SUPPORT the following types
// 1. `ConcreteTypePtrReceiver` - with methods (according to case I2)
// 1. `someMethod() int`
// declaration above SUPPORTs the following types
// 1. `*ConcreteTypePtrReceiver` - with methods (according to case L2)
// 1. `someMethod() int`
type InterfaceType interface {
someMethod() int
}
func main() {
var okX, okY bool
fmt.Printf("options: | type assertions to | interface value method receiver | interface value type | result for interface type | result for interface type \n")
fmt.Printf("---- | ---- | ---- | ---- | ---- | ---- \n")
fmt.Printf("case | `x.(`**T**`)` | type / pointer | value / pointer | `var x interface{}` | `var x InterfaceType` \n")
{
var x interface{} = ConcreteTypeTypeReceiver{1}
var y InterfaceType = ConcreteTypeTypeReceiver{1}
_, okX = x.(ConcreteTypeTypeReceiver)
_, okY = y.(ConcreteTypeTypeReceiver)
fmt.Printf("A | concrete type | type | value | %t | %t\n", okX, okY) // true / true
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;`
// `dynamic type of x`: ConcreteTypeTypeReceiver
// `type T`: ConcreteTypeTypeReceiver
// type ConcreteTypeTypeReceiver is identical to type ConcreteTypeTypeReceiver: result=true
}
{
var x interface{} = ConcreteTypeTypeReceiver{1}
var y InterfaceType = ConcreteTypeTypeReceiver{1}
_, okX = x.(*ConcreteTypeTypeReceiver) // panic: interface conversion: interface {} is main.ConcreteTypeTypeReceiver, not *main.ConcreteTypeTypeReceiver
_, okY = y.(*ConcreteTypeTypeReceiver) // panic: interface conversion: main.InterfaceType is main.ConcreteTypeTypeReceiver, not *main.ConcreteTypeTypeReceiver
fmt.Printf("B | pointer to concrete type | type | value | %t | %t\n", okX, okY) // false / false
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;`
// `dynamic type of x`: ConcreteTypeTypeReceiver
// `type T`: *ConcreteTypeTypeReceiver
// type ConcreteTypeTypeReceiver is not identical to type *ConcreteTypeTypeReceiver: result=false
}
{
var x interface{} = ConcreteTypeTypeReceiver{1}
var y InterfaceType = ConcreteTypeTypeReceiver{1}
_, okX = x.(InterfaceType)
_, okY = y.(InterfaceType)
fmt.Printf("C | interface type | type | value | %t | %t\n", okX, okY) // true / true
// `if T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T`
// `dynamic type of x`: ConcreteTypeTypeReceiver
// `interface T`: InterfaceType
// ConcreteTypeTypeReceiver implements InterfaceType: result=true
}
{
var x interface{} = &ConcreteTypeTypeReceiver{1}
var y InterfaceType = &ConcreteTypeTypeReceiver{1}
_, okX = x.(ConcreteTypeTypeReceiver) // panic: interface conversion: interface {} is *main.ConcreteTypeTypeReceiver, not main.ConcreteTypeTypeReceiver
_, okY = y.(ConcreteTypeTypeReceiver) // panic: interface conversion: main.InterfaceType is *main.ConcreteTypeTypeReceiver, not main.ConcreteTypeTypeReceiver
fmt.Printf("D | concrete type | type | pointer | %t | %t\n", okX, okY) // false / false
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;`
// `dynamic type of x`: *ConcreteTypeTypeReceiver
// `type T`: ConcreteTypeTypeReceiver
// type *ConcreteTypeTypeReceiver is not identical to type ConcreteTypeTypeReceiver: result=false
}
{
var x interface{} = &ConcreteTypeTypeReceiver{1}
var y InterfaceType = &ConcreteTypeTypeReceiver{1}
_, okX = x.(*ConcreteTypeTypeReceiver)
_, okY = y.(*ConcreteTypeTypeReceiver)
fmt.Printf("E | pointer to concrete type | type | pointer | %t | %t\n", okX, okY) // true / true
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;`
// `dynamic type of x`: *ConcreteTypeTypeReceiver
// `type T`: *ConcreteTypeTypeReceiver
// type *ConcreteTypeTypeReceiver is identical to type *ConcreteTypeTypeReceiver: result=true
}
{
var x interface{} = &ConcreteTypeTypeReceiver{1}
var y InterfaceType = &ConcreteTypeTypeReceiver{1}
_, okX = x.(InterfaceType)
_, okY = y.(InterfaceType)
fmt.Printf("F | interface type | type | pointer | %t | %t \n", okX, okY) // true / true
// `if T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T`
// `dynamic type of x`: *ConcreteTypeTypeReceiver
// `interface T`: InterfaceType
// *ConcreteTypeTypeReceiver implements InterfaceType: result=true
}
{
var x interface{} = ConcreteTypePtrReceiver{1}
//var y InterfaceType = ConcreteTypePtrReceiver{1} // cannot use ConcreteTypePtrReceiver literal (type ConcreteTypePtrReceiver) as type InterfaceType in assignment:
// ConcreteTypePtrReceiver does not implement InterfaceType (someMethod method has pointer receiver)
// x is empty interface `interface{}`
// any type satisfies empty interface = no `compiler static check failure` here
// y is `InterfaceType`
// to satisfy `InterfaceType` interface a type should have `someMethod() int` method
// ConcreteTypePtrReceiver{} is value - it is not a pointer
// we defined `someMethod() int` method on ConcreteTypePtrReceiver to operate on pointer
// only pointer to ConcreteTypePtrReceiver{} has `someMethod() int` method
// ConcreteTypePtrReceiver{} does not have `someMethod() int` method
// ConcreteTypePtrReceiver{} cannot satisfy `InterfaceType` = `compiler static check failure`
_, okX = x.(ConcreteTypePtrReceiver)
// _, okY = y.(ConcreteTypePtrReceiver) // N/A - see above
fmt.Printf("G | concrete type | pointer | value | %t | `%s`\n", okX, "static check failure") // true / <static check failure>
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;`
// `dynamic type of x`: ConcreteTypePtrReceiver
// `type T`: ConcreteTypePtrReceiver
// type ConcreteTypePtrReceiver is identical to type ConcreteTypePtrReceiver: result=true
}
{
var x interface{} = ConcreteTypePtrReceiver{1}
//var y InterfaceType = ConcreteTypePtrReceiver{1} // missing method someMethod - `compiler static check failure`
_, okX = x.(*ConcreteTypePtrReceiver) // panic: interface conversion: interface {} is main.ConcreteTypePtrReceiver, not *main.ConcreteTypePtrReceiver
// _, okY = y.(*ConcreteTypePtrReceiver) // N/A - see above
fmt.Printf("H | pointer to concrete type | pointer | value | %t | `%s`\n", okX, "static check failure") // false / <static check failure>
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;`
// `dynamic type of x`: ConcreteTypePtrReceiver
// `type T`: *ConcreteTypePtrReceiver
// type ConcreteTypePtrReceiver is not identical to type *ConcreteTypePtrReceiver: result=false
}
{
var x interface{} = ConcreteTypePtrReceiver{1}
//var y InterfaceType = ConcreteTypePtrReceiver{1} // missing method someMethod - `compiler static check failure`
_, okX = x.(InterfaceType) // panic: interface conversion: main.ConcreteTypePtrReceiver is not main.InterfaceType: missing method someMethod
// _, okY = y.(InterfaceType) // N/A - see above
fmt.Printf("I | interface type | pointer | value | %t | `%s`\n", okX, "static check failure") // false / <static check failure>
// `if T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T`
// `dynamic type of x`: ConcreteTypePtrReceiver
// `interface T`: InterfaceType
// InterfaceType require the method `someMethod() int` to be implemented
// for `type ConcreteTypePtrReceiver struct...`
// the method `someMethod() int` is defined on `*ConcreteTypePtrReceiver`
// the method `someMethod() int` is NOT defined on `ConcreteTypePtrReceiver`
// ConcreteTypePtrReceiver does not implement InterfaceType (only *ConcreteTypePtrReceiver): result=false
}
{
var x interface{} = &ConcreteTypePtrReceiver{1}
//var y InterfaceType = &ConcreteTypePtrReceiver{1}
_, okX = x.(ConcreteTypePtrReceiver) // panic: interface conversion: interface {} is *main.ConcreteTypePtrReceiver, not main.ConcreteTypePtrReceiver
// _, okY = y.(ConcreteTypePtrReceiver) // impossible type assertion: ConcreteTypePtrReceiver does not implement InterfaceType (someMethod method has pointer receiver)
// y is `InterfaceType`
// to satisfy `InterfaceType` interface a type should have `someMethod() int` method
// ConcreteTypePtrReceiver{} is value - it is not a pointer
// we defined `someMethod() int` method on ConcreteTypePtrReceiver to operate on pointer
// only pointer to ConcreteTypePtrReceiver{} has `someMethod() int` method
// ConcreteTypePtrReceiver{} does not have `someMethod() int` method
fmt.Printf("J | concrete type | pointer | pointer | %t | `%s`\n", okX, "static check failure") // false / <static check failure>
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;`
// `dynamic type of x`: *ConcreteTypePtrReceiver
// `type T`: ConcreteTypePtrReceiver
// type *ConcreteTypePtrReceiver is not identical to type ConcreteTypePtrReceiver: result=false
}
{
var x interface{} = &ConcreteTypePtrReceiver{1}
var y InterfaceType = &ConcreteTypePtrReceiver{1}
_, okX = x.(*ConcreteTypePtrReceiver)
_, okY = y.(*ConcreteTypePtrReceiver)
fmt.Printf("K | pointer to concrete type | pointer | pointer | %t | %t\n", okX, okY) // true / true
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;`
// `dynamic type of x`: *ConcreteTypePtrReceiver
// `type T`: *ConcreteTypePtrReceiver
// type *ConcreteTypePtrReceiver is identical to type *ConcreteTypePtrReceiver: result=true
}
{
var x interface{} = &ConcreteTypePtrReceiver{1}
var y InterfaceType = &ConcreteTypePtrReceiver{1}
_, okX = x.(InterfaceType)
_, okY = y.(InterfaceType)
fmt.Printf("L | interface type | pointer | pointer | %t | %t \n", okX, okY) // true / true
// `if T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T`
// `dynamic type of x`: *ConcreteTypePtrReceiver
// `interface T`: InterfaceType
// *ConcreteTypePtrReceiver implements InterfaceType: result=true
}
}
options: type assertions to interface value method receiver interface value type result for interface type result for interface type
case x.(T) type / pointer value / pointer var x interface{} var x InterfaceType
A concrete type type value true true
B pointer to concrete type type value false false
C interface type type value true true
D concrete type type pointer false false
E pointer to concrete type type pointer true true
F interface type type pointer true true
G concrete type pointer value true static check failure
H pointer to concrete type pointer value false static check failure
I interface type pointer value false static check failure
J concrete type pointer pointer false static check failure
K pointer to concrete type pointer pointer true true
L interface type pointer pointer true true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment