Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

can't you simply do this (from [1]) somewhere in your code to enforce?

    type T struct{}
    var _ I = T{}       // Verify that T implements I.
    var _ I = (*T)(nil) // Verify that *T implements I.
[1] https://golang.org/doc/faq#guarantee_satisfies_interface


Yes you could, but then you'd have to have both the declaration and the implementation of the interface in the same package. That would mean that if either of them is in a separate file, you'd have to import it. That in return, could easily call hellish compiler errors due to circular dependencies. In Go any circular dependency is an immediate compile error.

Looking at the link, the second advice is that you could require users to implement special functions such as ImplementsFooer() to explicitly declare which interface they're implementing. This could help, but this practice is not present in the codebases I've seen including the Go standard library (to the best of my knowledge).


A possible solution is to have a separate (otherwise unused) package in your codebase with just a test in it:

  //compile_test.go
  func TestThatThisModuleCompiles(t* testing.T) {}

  //list of "type implements interface" tests
  var _ mymodule.MyInterface = myothermodule.MyStruct{}
  ...
Then you just ensure that `go test` is run, e.g. by the CI.


That's a clever way to solve the issue. I think most Go codebases could benefit from such explicit checks where the language does not provide an unambiguous solution.

The interface issue has been on my mind for quite sometime. I had thought maybe declaring all interfaces in seperate files might help with the structure (like having the definitions in a header file in C), but the Go standard library does not use this approach. Interfaces and implementations are scattered across files and modules. Maybe I'm being too clever and we all know that Rob Pike always says that programmers should not be too clever. Maybe I should loosen up a bit, and treat Golang more like a pragmatic language. They did the best they could and produced a wonderful language. Any additional feature such as generics and explicit implements statements would have made the language much more complex.


This can go even further.

All the go files in a directory have to declare the same package name (`package mypkg`), with one exception: a test file (filename ends with `_test.go`) that has a package name that's the same as the normal package but ends with `_test` (as in `package mypkg_test`) is allowed to be in the same directory.

These are actually completely separate packages and you have to import the main package if you want to actually use it. But when you run `go test` it automatically complies and runs tests in both packages. This means that you can import both your package and a dependent package to make sure interfaces are satisfied without any circular dependencies.


Sibling comment shows one way to do it, but in most cases, at least for me, which is when both the struct and interface are in the same package it gets solved by the NewMyInterface method.

As it's return type is MyInterface, but it actually returns myStructure which causes the compiler to check the interface satisfying.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: