Golang package interface - go

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.

Related

Is there any way to preserve unused classes in Dart?

I started developing my own dependency injection package in dart just for fun. The problem I came across is that when a class is in it's own file and is not imported anywhere, dart's tree shaking will remove it and make it inaccessible. This makes it impossible for me to map implementation of some interface to the interface so I cannot ask context to give me implementation when I supply the interface. Here is what I mean:
import 'context/context.dart';
void main() {
Context context = Context();
Interface interface = context.getInstance<Interface>();
interface.works();
}
abstract class Interface {
void works();
}
And here is the implementation of the "Interface" abstract class:
#Singleton()
class Implementation implements Interface {
#override
void works() {
print('works');
}
}
If I import the file that contains the "Implementation" class, context is able to find it and map it but I want to avoid doing that. Is there any way to turn off the tree shaking or preserve the class without importing it ?

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

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

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
}
}

Autowiring interface vs class

If there are more than one implementation of an interface, then I would have to use #Qualifier to indicate which class I want to autowire with. Wouldn't it make more sense to autowire the class directly instead of interface?
This is what object oriented programming (especially abstraction and polymorphism) is about.
You build the classes independendent of concrete implementations and use an interface.
This allows you to change what implementation you use at any point.
Assume you have this:
public interface I{
void doSomething();
}
#Component("a")
public class A implements I{
public void doSomething(){
//...
}
public void doSomethingElse(){
//...
}
}
#Component("b")
public class B implements I{
public void doSomething(){
//...
}
}
If you use
#Autowired
private A yourVariable;
you might be tempted to use the doSomethingElse() method that is an implementation detail (by what reason whatsoever).
However, if you use
#Qualifier("a")
private I yourVariable;
this cannot happen as the method is not present in the interface.
This gives you the ability to swap the implementation at any time.
Wouldn't it make more sense to autowire the class directly instead of interface?
This pretty much depends on how exactly do you work with qualifiers but in general, the answer is "No", autowiring the class is a bad thing to do if you have an interface - you should always work by interface.
Here are the examples:
interface I { void foo(); }
class IImpl1 implements I {
void foo() {System.out.println("Impl1");
pubic void bar() {// another method - why not?}
}
class IImpl2 implements I { void foo() {System.out.println("Impl2"); }
Note, that an implementation IImpl1 has an additional method bar that doesn't belong to the interface I
Case 1:
#Component
public class Driver {
#Autowired
private IImpl1 i;
}
Here class Driver is tightly could to the concrete implementation IImpl1 in general I can call method bar from the Driver class because I have this implementation, but in this case if I'll have to switch the implementation of Driver in future you'll have to also change the code: both change the reference, and also get rid of calls to IImpl1.bar() that might be not that easy to do - its a change in logic. As a result, the whole polymorphic behavior is lost.
By far its the worst way to program.
Now, consider Case 2:
#Component
public class Driver {
#Autowired
#Qualifier("someLogicalName") // under the hood it spring will map it to IImpl1 but you don't know that here
I i;
}
In this case - the things are much better - you never couple the driver to the concrete implementation at the level of code. This means that in general its enough to change the qualifier to get another implementation. You can't call bar anymore - it won't compile.
You also do not know what the implementation will be injected. If in future the implementation of the component that actually implements the logic of "someLogicalName" will change (by that I mean that you'll create a new class IImpl3), you won't feel it here - you'll place that qualifier on that new class and all the places that use it will get that implementation automatically.
Case 3:
#Configuration
public class MyConfiguration {
#Bean
public Driver driver(#Qualifier("someLogicalName") I i) {
return new Driver(i);
}
}
public class Driver {
private final I i;
public Driver(I i) { // in real life this constructor can be generated by
// lombok or something, put it here for the sake of completeness
this.i = i;
}
}
This by far the most "clean" approach - conceptually its really similar to case 2, however in this case you don't place the qualifier at the level of Driver class at all, in fact, the class Driver is not even aware at the level of code / metadata that its related to Spring anyhow. Of course all the "advantages" of case 2 are also applicable here as well.

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.

Resources