29

How can I ensure that a type implements an interface at compile time? The typical way to do this is by failure to assign to support interfaces from that type, however I have several types that are only converted dynamically. At runtime this generates very gruff error messages, without the better diagnostics given for compile time errors. It's also very inconvenient to find at run time that types I expected to support interfaces, do in fact not.

Matt Joiner
  • 112,946
  • 110
  • 377
  • 526

5 Answers5

39

Assuming the question is about Go, e.g.

var _ foo.RequiredInterface = myType{} // or &myType{} or [&]myType if scalar

as a TLD will check that for you at compile time.

Dave C
  • 7,729
  • 4
  • 49
  • 65
zzzz
  • 87,403
  • 16
  • 175
  • 139
  • 1
    Does it slow down the compilation? If so, would it be a good practice to move that code to a "test" file? – andrew.fox Sep 07 '22 at 12:42
16

In the Go language there is no "implements" declaration by design. The only way to ask the compiler to check that the type T implements the interface I by attempting an assignment (yes, a dummy one). Note, Go lang differentiates methods declared on structure and pointer, use the right one in the assignment check!

type T struct{}
var _ I = T{}       // Verify that T implements I.
var _ I = (*T)(nil) // Verify that *T implements I.

Read FAQ for details Why doesn't Go have "implements" declarations?

smile-on
  • 2,073
  • 1
  • 20
  • 20
  • 2
    [http://play.golang.org/p/UNXt7MlmX8](http://play.golang.org/p/UNXt7MlmX8) to highlight the difference between pointer and struct assignment checks – smile-on Jan 05 '16 at 19:40
13

Extending the answer by @smile-on.

In How can I guarantee my type satisfies an interface?, which is part of the Frequently Asked Questions (FAQ) by the Go Authors, the following is stated:

You can ask the compiler to check that the type T implements the interface I by attempting an assignment using the zero value for T or pointer to T, as appropriate.

We can illustrate this with an example:

package main

type I interface{ M() }
type T struct{}

func (T) M() {}

//func (*T) M() {} //var _ I = T{}: T does not implement I (M method has pointer receiver)

func main() {
  //avoids allocation of memory
  var _ I = T{}       // Verify that T implements I.
  var _ I = (*T)(nil) // Verify that *T implements I.
  //allocation of memory
  var _ I = &T{}      // Verify that &T implements I.
  var _ I = new(T)    // Verify that new(T) implements I.
}

If T (or *T, accordingly) doesn't implement I, the mistake will be caught at compile time. See Non-interface methods in interface implementation.

Typically you check if a value implements an interface if you don't know its type. If it is known, the check is done by the compiler automatically. See Explanation of checking if value implements interface.

The blank identifier _ stands for the variable name, which is not needed here (and thus prevents a "declared but not used" error). (*T)(nil) creates an uninitialized pointer to a value of type T by converting nil to *T. See Have trouble understanding a piece of golang code.

This is the same value which, for example, var t *T has before assigning anything to it. See golang interface compliance compile type check. This avoids allocation of memory for an empty struct as you'd get with &T{} or new(T). See Have trouble understanding a piece of golang code.

Quotes edited to match example.

-3
package main

import (
    "fmt"
)

type Sayer interface {
    Say()
}

type Person struct {
    Name string
}

func(this *Person) Say() {
    fmt.Println("I am", this.Name)
}

func main() {
    person := &Person{"polaris"}

    Test(person)
}

func Test(i interface{}) {
    //!!here ,judge i implement Sayer
    if sayer, ok := i.(Sayer); ok {
        sayer.Say()
    }
}

The code example is here:http://play.golang.org/p/22bgbYVV6q

Kaicui
  • 3,795
  • 1
  • 15
  • 20
-6

I don't like the idea of making compiler throw errors by putting dummy lines in the main code. That's a smart solution that works, but I prefer to write a test for this purpose.

Assuming that we have:

type Intfc interface { Func() }
type Typ int
func (t Typ) Func() {}

This test makes sure Typ implements Intfc:

package main

import (
    "reflect"
    "testing"
)

func TestTypes(t *testing.T) {
    var interfaces struct {
        intfc Intfc
    }
    var typ Typ
    v := reflect.ValueOf(interfaces)
    testType(t, reflect.TypeOf(typ), v.Field(0).Type())
}

// testType checks if type t1 implements interface t2
func testType(t *testing.T, t1, t2 reflect.Type) {
    if !t1.Implements(t2) {
        t.Errorf("%v does not implement %v", t1, t2)
    }
}

You can check all of your types and interfaces by adding them to TestTypes function. Writing tests for Go is introduced here.

Mostafa
  • 26,886
  • 10
  • 57
  • 52
  • 4
    Eh, no. Writing a test case using reflection just to avoid a compiler's statical type checking is IMO not advisable. – zzzz May 12 '12 at 17:08
  • 3
    Go is a statically typed language. What's wrong with a static type check? Dynamic type checking is reasonable iff static type checking is not possible, IMHO. – zzzz May 12 '12 at 18:39
  • 2
    what if you miss a test? – vimdude May 02 '14 at 12:51