Go Interfaces: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
Line 60: Line 60:
The method set contains method signatures, so the interface type does not define ''how'' the behavior is implemented, but just the behavior's contract. The interfaces allow us to hide the incidental details of the implementation. The behavior implementation details are contained by user-defined types, via methods.
The method set contains method signatures, so the interface type does not define ''how'' the behavior is implemented, but just the behavior's contract. The interfaces allow us to hide the incidental details of the implementation. The behavior implementation details are contained by user-defined types, via methods.


==Interface Name Convention==
===Interface Name Convention===


If the interface type contains only one method, the name of the interface starts with name of the method and ends with the ''er'' suffix.
If the interface type contains only one method, the name of the interface starts with name of the method and ends with the ''er'' suffix.

Revision as of 01:05, 18 April 2016

Internal

Overview

Go has an unique interface system that allows modeling behavior rather than modeling types. An interface declares the behavior of a type. The availability of interfaces in the language allows for polymorphism.

There is no need to declare that an interface is implemented, the compiler does the work of determining whether the values of a type satisfy an interface. Is this a good thing? As far as I can tell, I can't say whether a specific type implements an interface, short of browsing all methods in the package, looking for receivers of that specific type. This does not help code readability. So, if a type implements the methods of an interface, a value of the type can be stored in a value of that interface type and the compiler ensure the assignments are correct at compile-time.

If a method call is made against an interface value, the equivalent method of the stored user-defined value - whatever that happens to be at the moment - it is executed. This is an expression of the polymorphic nature of the language. The user-defined type is often called a concrete type.

Interfaces in Go tend to be small, exposing only a few functions, or just one function.

TODO

Method Sets

Each type has a method set associated with it. There are interface method sets and user-defined types method sets.

In a method set, each method must have a unique non-blank method name.

The language specification defines the method sets here here.

Interface Method Set and the Interface Type Declaration

An interface method set is the specified in the interface type declaration. The interface type declaration has the only purpose of defining the method set and giving it a name - the interface name.

The interface declaration is introduced by the type keyword, to indicated that this is a user-defined type, followed by the interface name and the keyword interface, followed by the method set declaration between curly braces. Unlike in the struct's case, we don't define fields.

type MyInterface interface {
 
    <function-name-1><function-signature-1>
    <function-name-2><function-signature-2>
     ...
}

Example:

type A interface {

    m1(i int) int
    m2(s string) string

}

The method set is a list of method signatures designating methods a type must expose in order to implement the interface. See making a type implement an interface.

The method set contains method signatures, so the interface type does not define how the behavior is implemented, but just the behavior's contract. The interfaces allow us to hide the incidental details of the implementation. The behavior implementation details are contained by user-defined types, via methods.

Interface Name Convention

If the interface type contains only one method, the name of the interface starts with name of the method and ends with the er suffix.

When multiple methods are declared within an interface type, the name of the interface should relate to its general behavior.

User-Defined Type Method Set

The method set of a user-defined type consists of all methods declared with a receiver of that type T.

The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T. The method set of the corresponding pointer type always includes by default the methods declared with the value receiver of the type.

Making a Type Implement an Interface

A type (struct, anything else?) can be made to implement an interface by making the type to expose all methods from the interface's method set. "Exposing" a method means that a method with the same name and signature is declared to use the type in question as value or pointer receiver.

This is called duck typing. There is no "implements" or "extends" keyword in Go.

The example that follows shows how a type B implements interface A:

//
// The interface A declares a method set containing a single method m()
//
type A interface {
    m()
}

//
// At this point, the struct B is not yet linked to the interface A in any 
// way (it does not implement interface A)
//
type B struct {
    i int
}

//
// We make B implement interface A by declaring B as a value receiver for 
// m(). Pointer receiver also works. Since A only contains m(), B implements 
// A by the virtue of duck typing
//
func (b B) m() {
    // simply reports the value of i
    fmt.Println(b.i)
}

...

//
// B now implements A, so A methods can be invoked on B
//
b := B{1}
b.m()

...

Interface instances can be used as arguments to functions. See passing interfaces to functions.

Passing Interfaces to Functions

Interfaces can be used as arguments to functions. Passing an interface instance insures that the function body can rely on the fact the interface methods are available on the passed instance.

With the example above, we declare a function f() that expects an interface A and we pass a B instance when invoking the function:

...

func f(a A) {
    a.m()
}

...
b := B{1}
f(b)
...

Note that the B instance can be passed by value (as in the example above) or by reference (as in the example below). Both cases work:

...
b := B{1}
f(&b)
...

or (same thing)

...
bPtr := new(B)
f(bPtr)
...

TODO further discussion on the merits of passing the interface by value and by reference.

Interfaces as Fields

Interfaces can be used as fields.

Implementation Details

An interface variable is a two-word data structure.

The first word contains a pointer to an internal table called iTable, which contains type information about the stored value: the type of the value that has been stored (the concrete type) and a list of methods associated with the value.

The second word is a reference to the stored value.

The combination of type information and pointer binds the relationship between the two values.

More details "Go in Action" page 125.