Unions of type sets

General interfaces … Union elements denote unions of type sets: // The Float interface represents all floating-point types // (including any named types whose underlying types are // either float32 or float64). type Float interface { ~float32 | ~float64 } Here we see our first example of a union of type sets. The example shows an interface of all types with an underlying float type. The equivalent for integer types is a bit longer, due to the large number of distinct integer types in Go, but would look like:


Restrictions on underlying type terms

General interfaces … In a term of the form ~T, the underlying type of T must be itself, and T cannot be an interface. type MyInt int interface { ~[]byte // the underlying type of []byte is itself ~MyInt // illegal: the underlying type of MyInt is not MyInt ~error // illegal: error is an interface } Once again, the spec examples are pretty well explained. TL;DR; the ~ prefix must always be associated with an underlying data type.

How-Tos

28 min watch


I'm officially a Go contributor! (and you can be, too)

Learn how the Go proposal and change process works, with a real world example.


Interface examples with type elements

Let’s look at some interface examples from the spec: General interfaces … // An interface representing only the type int. interface { int } // An interface representing all types with underlying type int. interface { ~int } // An interface representing all types with underlying type int that implement the String method. interface { ~int String() string } // An interface representing an empty type set: there is no type that is both an int and a string.

Subscribe to Boldly Go: Daily

Every day I'll send you advice to improve your understanding of Go. Don't miss out! I will respect your inbox, and honor my privacy policy.

Unsure? Browse the archive.


Interfaces don't contain interfaces

As we learned recently, Go interface elements may contain a type term of a non-interface type. It’s worth re-iterating that these are non-interface types. In particular, as the spec states: General interfaces … By construction, an interface’s type set never contains an interface type. That is to say, that the following is invalid: type interface foo { /* some interface elements */ } type interface bar { foo } Actually, I lied.


"Duck Typing" defined

I’ve already introduced the concept of duck typing, but now we have more or less a formal definition: General interfaces … The quantification “the set of all non-interface types” refers not just to all (non-interface) types declared in the program at hand, but all possible types in all possible programs, and hence is infinite. Similarly, given the set of all non-interface types that implement a particular method, the intersection of the method sets of those types will contain exactly that method, even if all types in the program at hand always pair that method with another method.


Interface type sets

With what we’ve learned so far about interfaces, we can now draw some general conclusions about the precise definitions of an interfce’s type set. The spec summarizes nicely. General interfaces … Together with method specifications, these elements enable the precise definition of an interface’s type set as follows: The type set of the empty interface is the set of all non-interface types. The type set of a non-empty interface is the intersection of the type sets of its interface elements.


General interfaces

Today we’re venturing into generics territory. General interfaces In their most general form, an interface element may also be an arbitrary type term T, or a term of the form ~T specifying the underlying type T, or a union of terms t1|t<sub<>2|…|tn. We haven’t actually learned about type terms yet–they’re coming in a few weeks. But for now, the TL;DR is that they let us specify a type by its name, rather than by its method(s).

How-Tos

30 min watch


How to bootstrap a Go project on GitHub Actions

I outline bootstrapping steps for a new Go project with GitHub Actions to run tests, lint code, and ensure secure project setup.


Embedded interfaces

Embedded interfaces In a slightly more general form an interface T may use a (possibly qualified) interface type name E as an interface element. This is called embedding interface E in T. The type set of T is the intersection of the type sets defined by T’s explicitly declared methods and the type sets of T’s embedded interfaces. In other words, the type set of T is the set of all types that implement all the explicitly declared methods of T and also all the methods of E.


Anonymous interfaces

Today we pick up the second half of an example we started with yesterday: Similarly, consider this interface specification, which appears within a type declaration to define an interface called Locker: type Locker interface { Lock() Unlock() } If S1 and S2 also implement func (p T) Lock() { … } func (p T) Unlock() { … } they implement the Locker interface as well as the File interface. We’ve already discussed that a single type may automatically satisfy multiple interfaces, so there’s not much to add here.