Based on a previous talk named "Understanding the interface", in this talk I:
- discuss the pros and cons of interfaces,
- introduce the concepts from the generics draft for Go2 type parameters and contracts, and
- compare the two approaches.
int: // t is of type int fmt.Println(“got int %d”, t) default: // t is of type interface{} fmt.Println(“not sure what type”) } } type assertions from interface to concrete type
fmt.Stringer: // s is of type fmt.Stringer fmt.Println(s.String()) default: // s is of type interface{} fmt.Println(“not sure what type”) } } type assertions from interface to interface
fmt.Stringer : implement String() string - json.Marshaler : implement MarshalJSON() ([]byte, error) - json.Unmarshaler : implement UnmarshalJSON([]byte) error - ... and adapt their behavior accordingly. Tip: Always look for exported interfaces in the standard library. type assertions as extension mechanism
interface { Header() Header Write([]byte) (int, error) WriteHeader(int) } How could you add one more method without breaking anyone’s code? type assertions as evolution mechanism
points Implicit satisfaction: - break dependencies Type assertions: - to extend behaviors - to classify errors - to maintain compatibility In conclusion
container types: • container/heap ◦ Provides only high level functions (Push, Pop, etc) ◦ Requires the user to implement the Heap interface • container/ring ◦ Provides a type Element containing a interface{} ◦ Requires constant type conversions, loses compile time checks.
func Length(type T length)(x T) int { return len(x) } Length([]int)([]int{1, 2, 3}) // 3 Length(map[int]int)(map[int]int{1: 1}) // 1 A type with length
methods, contracts on anything. → all interfaces can be represented as contracts contract Stringer(x T) { type Stringer interface { var s string = x.String() String() string } } Interfaces vs Contracts
contracts can be represented as interfaces contract comparable(v T) { var b bool = v < v } contract comparable(v T) { var b bool = v.Equal(v) } Interfaces vs Contracts
so unlike interfaces: • They hide no implementation • They don’t provide dynamic dispatching This is has some good effects: • the type system once compiled doesn’t change. • there’s no change to the reflect package.
bool = v.Equal(v) } What is the type of the Equal method? • func (v T) Equal(x T) bool • func (v *T) Equal(x T) bool • func (v T) Equal(x interface{}) bool contracts are probably too smart
Type parameters are great! • A library of concurrency patterns? • Functional programming in Go? Contracts are interesting, but probably *too smart* for Go. I hope to see new iterations of the draft simplifying the concepts.