Why does Go allow a struct to implement an unexported interface present in a different package? - go

I wrote a sample code to understand how the unexported interface works. In the below example, I have declared the unexported repoInterface in the service package.
TestRepo struct in the repo package implements the unexported repoInterface without any issues.
Code structure
repo
repo.go
service
service.go
main.go
service.go
// service/service.go
// this is the interface which the TestRepo struct implements in repo package
type repoInterface interface{
GetName() string
}
type TestService struct{
repo repoInterface
}
func NewTestService(r repoInterface) TestService {
return TestService{
repo: r,
}
}
func (s TestService) GetName() string {
return s.repo.GetName()
}
repo/repo.go
// repo/repo.go
type TestRepo struct{
name string
}
func NewTestRepo(name string) TestRepo {
return TestRepo{
name: name,
}
}
// implements repoInterface present in service package
func (r TestRepo) GetName() string {
return r.name
}
main.go
func main() {
testRepo := repo.NewTestRepo("hello")
testService := service.NewTestService(testRepo)
fmt.Println(testService.GetName())
}
// Output
// hello
My assumption so far:
This isn't possible since repo and service
are different packages.
TestRepo struct present in repo package cannot implement the Unexported interface present in the service package.
This is the reason why we export interfaces.
Now I realized that this is not true and my understanding is wrong.
Question:
Why does Go allow to implement an unexported interface present in a different package?

service.NewTestService package function requires any value that implements the type interface{ GetName() string }.
repo package exports a type TestRepo which exposes a method GetName() string.
Upon passing the repo.TestRepo to the service.NewTestService function like in service.NewTestService(testRepo), the value implements the interface by providing the expected method set.
All good.
That the type service.repoInterface declares a not exported identifier only discriminates the packages that can use that interface name.
I have reproduced your example on the play https://go.dev/play/p/bp6z2HjwdLS
An interface type declaration containing a not exported identifier is a sealed interface.
Those sealed interfaces can not be implemented by a foreign package.
It can be a not exported method name like in
type Fooer interface {
Foo()
sealed()
}
Try here https://go.dev/play/p/3Syh7R0uS-q
It can also declare a method using a not exported argument type,
type Foo interface {
GetName() string
GetName2() sealed
}
type sealed int

Related

Flamingo: Struct not assignable to Interface

I am using flamingo to build an application. I have a module in my source with a structure resembling as below.
some_interface.go
package something
type SomeInterface interface {
someMethod()
}
some_struct.go
package something
type SomeStruct struct {
}
func(s *SomeStuct) someMethod() {
}
Binding in some module
package something
type Module struct{}
func (*Module) Configure(injector *dingo.Injector) {
injector.BindMulti(new(SomeInterface)).To(new(SomeStruct))
}
when I run go run main.go serve, I get the following error
panic: something#SomeStruct not assignable to something#SomeInterface
Update
This only happens when I have methods in my interface. If I remove the method from my interface. It seems to work.
My bad. Found the solution. Interface methods should be exported.
some_interface.go
package something
type SomeInterface interface {
someMethod()
}
some_struct.go
package something
type SomeStruct struct {
}
func(s *SomeStuct) someMethod() {
}

Providing Access to package level variable via public getter - How to return the instance?

I have a package level variable that I instantiate at the startup of the application. Even though it is declared to be package level, I need to access it from outside the package as well. To do that, I have a function that returns the variable.
package app
var myService MyService
type MyService interface {
DoThis()
DoThat()
}
func Initialize() {
// initialise other stuff
myService = initMyService()
}
func GetMyService() MyService {
return myService
}
Now from outside of the app package, when I need to do something with MyService, I do following.
ms := app.GetMyService()
ms.DoThis()
Here I have following questions.
Doesn't the GetMyService() function return copies of myService each time it is invoked?
If that is the case, if I return a pointer to the myService inside that function, does it solve that problem by returning a reference to the single myService instance that was initially instantiated?
var myService MyService here MyService is an interface. So you can implement it with pointer receiver methods or value receiver methods.
As go tour tour.golang.org/methods/8 mentioned,
There are two reasons to use a pointer receiver.
The first is so that the method can modify the value that its receiver
points to.
The second is to avoid copying the value on each method call. This can
be more efficient if the receiver is a large struct...
If you implement MyService with pointer receiver methods, It will not copy the receiver in every call.
And please refer golang.org/doc/faq Should I define methods on values or pointers?. There is a good explanation for it too.
sample implementation like below
type doer struct {
// any fields
}
func (d *doer) DoThis() {
// any implementation
fmt.Println(`do this`)
}
func (d *doer) DoThat() {
// any implementation
fmt.Println(`do that`)
}
func initMyService() MyService{
return &doer{
// init doer fields
}
}

Golang package interface

I am bit new to golang and I have a question about packages and interfaces.
If I have package1, that needs to use implementation of an interface that can be swapped in future with other implementation, would that be possible?
some pseudo code
package implementation contains current implementation of interface
type TestI interface {
M1()
}
package implementation
type Impl struct {}
funct (i *Impl) M1 ( ... do something )
package package1
import TestI somehow and call M1 method but with flexibility to swap it with other implementation of this interface in future?
package package1 should use implementation without knowing about it (something like DI in c# or java, package should only know about interface, and not about implementation)
Where should TestI interface be defined? Sorry if this is a bit confusing, just trying to get my head around it.
This is equivalent in c#
ITest {
SetClass(Class1 cl);
}
// package1
class Class1 {
private ITest test {get; set;}
public void SomeMethod() {
// i want to somehow set this in other package
test.SetClass(this);
}
}
// package2
class Test implements ITest {
private Class1 cl;
SetClass(Class1 c) {
this.c1 = c;
}
}
Unless you are writing an interface-first application, it is generally best to write the concrete implementations without declaring any interfaces. Then the users of that package can declare the necessary interfaces. For example:
type Implementation struct {
...
}
func (i Implementation) FuncA() {...}
func (i Implementation) FuncB() {...}
If some type that implements FuncA is required, you can declare:
type IntfA interface {
FuncA()
}
Any type that has the method FuncA implements IntfA, and Implementation fits that description, so you can pass an instance of Implementation to a function that needs IntfA.
Similarly, if you need an interface that has both FuncA and FuncB, you can declaret:
type IntfAB interface {
FuncA()
FuncB()
}
and Implementation also implements IntfAB.
So, ideally, you would declare the interface you need where you use it, and any type with a matching set of methods can be used for the implementation of that interface.
If you are writing based on an existing interface, then you can put that interface in a separate package than the implementation, or you can keep the interface and the implementation in the same package, whichever makes more sense for your use case.

Embeded interface : struct doesn't implement method

I don't understand why interface composition doesn't " inherit" the methods from the parent interface when it is satisfied in the implementation.
package main
import (
"fmt"
)
type TestRepository interface {
FindById(int) (error)
}
type TestService interface {
TestRepository
Method(id int) error
}
type testService struct {
implRepository TestRepository
}
func NewTestService(r TestRepository) TestService {
return &testService{implRepository: r}
}
When compiling this code i'm getting : *testService does not implement TestService (missing FindById method) while i'm actually expecting it to implement it since the type of "implRepository" is TestRepository.
It works if i do :
func NewTestService(r TestRepository) *testService {
return &testService{implRepository: r}
}
But it kind of defeat the purpose of the interface ( as far as the service one goes at least )
What am i missing / how should it be done ?
The answer to your question is simply "you aren't composing the interface the way you need to." You have made TestRepository a struct member - that is not going to "inherit" the methods on that interface. What you need is the following:
type testService struct {
TestRepository
}
func NewTestService(r TestRepository) TestService {
return &testService{TestRepository: r}
}
Of course, the struct testService still need to implement Method(id int) error to actually work.

In Kotlin, how can I work around the inherited declarations clash when an enum class implements an interface?

I define an enum class that implements Neo4j's RelationshipType:
enum class MyRelationshipType : RelationshipType {
// ...
}
I get the following error:
Inherited platform declarations clash: The following declarations have the same JVM signature (name()Ljava/lang/String;): fun <get-name>(): String fun name(): String
I understand that both the name() method from the Enum class and the name() method from the RelationshipType interface have the same signature. This is not a problem in Java though, so why is it an error in Kotlin, and how can I work around it?
it is a kotlin bug-KT-14115 even if you makes the enum class implements the interface which contains a name() function is denied.
interface Name {
fun name(): String;
}
enum class Color : Name;
// ^--- the same error reported
BUT you can simulate a enum class by using a sealed class, for example:
interface Name {
fun name(): String;
}
sealed class Color(val ordinal: Int) : Name {
fun ordinal()=ordinal;
override fun name(): String {
return this.javaClass.simpleName;
}
//todo: simulate other methods ...
};
object RED : Color(0);
object GREEN : Color(1);
object BLUE : Color(2);
The example above is working with an interface having a property name instead of a function name().
interface Name {
val name: String;
}
enum class Color : Name {
Blue
}

Resources