Unable to successfully run packaged version of functional options pattern (FOP) that uses Go generics and embedded interfaces - go

In an effort to learn idiomatic Go, I am trying to write a reusable package (saybase for purposes of this question). This package provides a Base interface, with minimally required functions and a BaseStruct to implement those functions. Base is to be embedded in other application-domain specific packages, say composite packages.
type Base interface {
defaultCfg()
setID(string)
setEnqSize(int)
}
type BaseStruct struct {
id string
enqSize int
}
func New[T Base](t T, opts ...func(T)) T {
// Code is provided in playground below.
}
type Comp interface {
Base
setConn(string)
}
type CompStruct struct {
Base
conn string
}
// Other code in playground.
Critical requirements for me:
Create new instances of composite structs using some constructional pattern like builder or functional options pattern. I was able to get FOP working with the New function.
Provide a 'default' set of values using defaultCfg for the base and each composite, which can be overridden during the process of construction of the composite structures.
Disallow modification of the structs' fields directly. Modifications occur either through private setters for construction, and public messages for state changes.
I'm basically writing an actor model framework that uses an actor-tree based communication pattern. The framework mostly works (message passing, etc.) barring this ability to reliably construct the actors prior to their launch.
Being a novice at Go, I have hit a brick wall trying to understand and resolve run-time panic when packaging my functions.
I wrote up some minimal code to isolate the issue. The playgrounds below do not have any actor model code, just renamed units to demonstrate my issue. The working code for instantiation is in this playground. The output of working code:
defBase: {id:"DefaultID", enqSize:1}
idBase: {id:"Non-Def-ID", enqSize:1}
myBase: {id:"Non-Def-ID", enqSize:4}
defComp: {Base:{id:"DefaultID", enqSize:1}, conn:"DefaultConn"}
idComp: {Base:{id:"Non-Def-ID", enqSize:1}, conn:"DefaultConn"}
myComp: {Base:{id:"Non-Def-ID", enqSize:4}, conn:"Non-Def-Conn"}
Program exited.
However, when I re-packaged the code as in this non-working playground, the code runs to a panic when constructing even the default composite structure. Output (the first two lines are just a check for me.):
Type of BaseStruct is: base.BaseStruct
Type of CompStruct is: comp.CompStruct
defBase: {id:"DefaultID", enqSize:1}
idBase: {id:"Non-Def-ID", enqSize:1}
myBase: {id:"Non-Def-ID", enqSize:4}
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x482f44]
goroutine 1 [running]:
play.ground/comp.(*CompStruct).play.ground/base.defaultCfg(0x1?)
<autogenerated>:1 +0x24
play.ground/base.withDefault[...].func1()
/tmp/sandbox109723629/base/base.go:16 +0x2f
play.ground/base.New[...]({0x4bafe0?, 0xc00006e060}, {0x0, 0x0, 0x1})
/tmp/sandbox109723629/base/base.go:6 +0x47
main.main()
/tmp/sandbox109723629/prog.go:34 +0x379
Program exited.
I have a workaround, as taken from Dave Cheney, where the New function gets repeated in the comp package as well. Definition is something like:
func NewComp(options ...func(Comp)) Comp {
var e Comp = &CompStruct{
Base: base.NewBase(),
conn: "DefaultConn",
}
for _, option := range options {
option(e.(Comp))
}
return e.(Comp)
}
However, I would like to avoid creating variants of New for each composite package that is dependent on Base (or another composite). Referring to the complete code in either playground, I would also like to avoid specifying the instance of a generic for each WithXxx option; and instead have it use the instance specified for the New function. Is that possible?
Any pointers for a fix and any suggestions for writing code or this post better are gladly welcome.
Thank you.

The program panics because the CompStruct.Base field is nil. Initialize the field by changing all uses of new(comp.CompStruct) with &comp.CompStruct{Base: &base.BaseStruct{}}.

Related

Interface management in Go

I know this has been asked in various forms many times before but I just can't seem to implement what I'm learning in the way that I need. Any help is appreciated.
I have a series of exchanges which all implement roughly the same APIs. For example, each of them have a GetBalance endpoint. However, some have one or two unique things which need to be accessed within the functions. For example, exchange1 needs to use a client when calling it's balance API, while exchange2 requires both the client variable as well as a clientFutures variable. This is an important note for later.
My background is normal OOP. Obviously Go is different in many ways, hence I'm getting tripped up here.
My current implementation and thinking is as follows:
In exchanges module
type Balance struct {
asset string
available float64
unavailable float64
total float64
}
type Api interface {
GetBalances() []Balance
}
In Binance module
type BinanceApi struct {
key string
secret string
client *binance.Client
clientFutures *futures.Client
Api exchanges.Api
}
func (v *BinanceApi) GetBalance() []exchanges.Balance {
// Requires v.client and v.clientFutures
return []exchanges.Balance{}
}
In Kraken module
type KrakenApi struct {
key string
secret string
client *binance.Client
Api exchanges.Api
}
func (v *KrakenApi) GetBalance() []exchanges.Balance {
// Requires v.client
return []exchanges.Balance{}
}
In main.go
var exchange *Api
Now my thought was I should be able to call something like exchange.GetBalance() and it would use the GetBalance function from above. I would also need some kind of casting? I'm quite lost here. The exchange could either be Binance or Kraken--that gets decided at runtime. Some other code basically calls a GetExchange function which returns an instance of the required API object (already casted in either BinanceApi/KrakenApi)
I'm aware inheritance and polymorphism don't work like other languages, hence my utter confusion. I'm struggling to know what needs to go where here. Go seems to require loads of annoying code necessary for what other languages do on the fly 😓
using *exchanges.Api is quite weird. You're wanting something that implements a given interface. What the underlying type is (whether it's a pointer or a value receiver) is not important, so use exchanges.Api instead.
There is another issue, though. In golang, interfaces are implicit (sometimes referred to as duck-type interfaces). Generally speaking, this means that the interface is not declared in the package that implements it, but rather in the package that depends on a given interface. Some say that you should be liberal in terms of what values you return, but restrictive in terms of what arguments you accept. What this boils down to in your case, is that you'd have something like an api package, that looks somewhat like this:
package api
func NewKraken(args ...any) *KrakenExchange {
// ...
}
func NewBinance(args ...any) *BinanceExchange {
}
then in your other packages, you'd have something like this:
package kraken // or maybe this could be an exchange package
type API interface {
GetBalances() []types.Balance
}
func NewClient(api API, otherArgs ...T) *KrakenClient {
}
So when someone looks at the code for this Kraken package, they can instantly tell what dependencies are required, and what types it works with. The added benefit is that, should binance or kraken need additional API calls that aren't shared, you can go in and change the specific dependencies/interfaces, without ending up with one massive, centralised interface that is being used all over the place, but each time you only end up using a subset of the interface.
Yet another benefit of this approach is when writing tests. There are tools like gomock and mockgen, which allow you to quickly generate mocks for unit tests simply by doing this:
package foo
//go:generate go run github.com/golang/mock/mockgen -destination mocks/dep_mock.go -package mocks your/module/path/to/foo Dependency
type Dependency interface {
// methods here
}
Then run go generate and it'll create a mock object in your/module/path/to/foo/mocks that implements the desired interface. In your unit tests, import he mocks package, and you can do things like:
ctrl := gomock.NewController(t)
dep := mocks.NewDependencyMock(ctrl)
defer ctrl.Finish()
dep.EXPECT().GetBalances().Times(1).Return(data)
k := kraken.NewClient(dep)
bal := k.Balances()
require.EqualValues(t, bal, data)
TL;DR
The gist of it is:
Interfaces are interfaces, don't use pointers to interfaces
Declare interfaces in the package that depends on them (ie the user), not the implementation (provider) side.
Only declare methods in an interface if you are genuinely using them in a given package. Using a central, overarching interface makes this harder to do.
Having the dependency interface declared along side the user makes for self-documenting code
Unit testing and mocking/stubbing is a lot easier to do, and to automate this way

Using instances of generic types as return value type in a Hyperledger chain code written in GO

In my project, I am using a wrapper structure, that is defined similar to this:
type Wrapper[T any] struct {
Foo int
Data T
}
Additionally, my chain code offers a method with the following signature
func(contract *MyContract) DoSomething() *Wrapper[mypkg.Bar]
where Bar is a simple structure defined - for example - like this:
package mypkg
struct Bar {
Foo string
Bar string
}
Anyhow, if I try to deploy my chaincode, I get the following error:
Error compiling schema for MyContract[DoSomething]. Return schema invalid. Object has no key 'Wrapper[[]<part of module name>'
Strangely, the part with Wrapper[[]<part of module name> is cropped. So only part of the module name is showing, and, as you can see, the bracketing is wrong: The second closing bracket is missing (so that is not a mistake made by me). The name of my module is the link to the GitHub repository.
I have tried to manually replace the generic type T in Wrapper with Bar by creating the structure
type WrapperBar struct {
Foo int
Data Bar
}
If I now adapt the function signature to
func(contract *MyContract) DoSomething() *WrapperBar
it works just fine. Unfortunately, I am using the structure Wrapper several times with different
type instantiations. So although creating all the types manually would be a workaround, it is obviously not a very elegant one.
Is there another workaround so that I can still use my generic Wrapper structure?
I am currently using go in version 1.18 and fabric-contract-api-go in version v1.1.1.
The Go contract-api at this time doesn't support Go Generics, the only workarounds I can suggest are the one that you have tried noted in this question or to write your chaincode without using the contract API, there is an example here https://github.com/hyperledger/fabric-samples/tree/main/chaincode/marbles02/go of an implementation that doesn't use the contract-api.
Your implemention will have to do more work in your chaincode such as providing your own method dispatching, validating and unmarshalling the input data
You could raise an issue at https://github.com/hyperledger/fabric-contract-api-go and ideally also contribute a PR that addresses this issue as I can't say when or if this would ever be supported.

Inheritance in golang

I'm trying to create a template method that should be executed a certain other method is called.
For example:
func main(){
onInit()
}
func onInit(){
var Instance entity.EntityInstance
Instance.Init()
//do something
}
Another source file, instance.go
type EntityInstance struct{
name string
version string
}
func (instance *EntityInstance) Init(){
// do some initialization
}
The main method is in different code base/app and uses the Instance app to invoke certain initializations.
Currently the user writing this above main method needs to explicitly call the Instance.init()
The objective is for the developers (in this case one who implements the main method) only concern themselves with any of their custom initializations and not worry about calling "Instance.Init()". The OnInit() invoke should take care of "Instance.Init()" implicitly.
Any help to get me started in the right direction ?
EDIT: I do understand that the exact OOP concepts cannot be translated here in Golang but all I'm looking for is the appropriate approach. Clearly, I need to change the way I think of design in here but just don't know how.
Your question is a little unclear, I suspect because you are trying to directly translate ideas and idioms from another language, you should resist doing that. However, if you want an implicit init for a package in Go, you can use the magic function name
func init(){}
https://golang.org/doc/effective_go.html#init
Finally, each source file can define its own niladic init function to
set up whatever state is required. (Actually each file can have
multiple init functions.) And finally means finally: init is called
after all the variable declarations in the package have evaluated
their initializers, and those are evaluated only after all the
imported packages have been initialized.
Be careful with this though, it is implicit behaviour and could cause mysterious bugs if your callers don't know it is happening when they import your package.

Why Go design not to mark as error when assign a variable to whatever interface that has same signature

I'm just start learning Go, most of my background came from Java, Ruby.
I just wonder that, from my example, why Go language designer intentionally design to not specify an interface type when implement an interface. So that if someone accidentally try to assign an object to an interface that match a signature but doesn't intend to implement that interface, that would lead to be a bug and cannot be catch at a compile time.
You can try at this: https://play.golang.org/p/1N0kg7m4eE
package main
import "fmt"
type MathExpression interface {
calculate() float64
}
type AreaCalculator interface {
calculate() float64
}
type Square struct {
width, height float64
}
//This implementation intend to implement AreaCalculator interface
func (s Square) calculate() float64 {
return s.width * s.height
}
func main() {
//Suppose that a developer got this object from
//somewhere without a knowledge that object is a Square struct
mysteryStruct := Square{width: 4, height: 3}
var areaCalculator AreaCalculator = mysteryStruct
fmt.Println("Area of something:", areaCalculator.calculate())
var mathExpression MathExpression = mysteryStruct
fmt.Println("This should not work:", mathExpression.calculate())
}
One advantage of "implicitly satisfied" interfaces (ones where types don't need to explicitly declare that they implement them) is that interfaces can be created after the fact. You can see several types that have a method in common, perhaps in different packages, and decide to write a function that can accept any of them by calling for a new interface that specifies that method.
Also, Go's approach to interfaces lets you write an abstraction of the behavior of a type in an existing package, without modifying the original package. The first example that comes to my mind is the File interface in the net/http package:
type File interface {
io.Closer
io.Reader
io.Seeker
Readdir(count int) ([]os.FileInfo, error)
Stat() (os.FileInfo, error)
}
It represents a file that can by served by an http.FileServer. Normally it is an os.File, but it could be anything that fulfills the interface. For example, I think someone has made an implementation that serves files out of a zip archive.
Since the net/http package is defined in the standard library, it might have been possible to explicitly declare that os.File implements http.File—but it would have made the os package depend on the net/http package. This is a circular dependency, because net/http depends on os.
In an inheritance-based language, someone who was trying to do this would probably just give up on using an interface, and make http.FileServer require that all files be subclasses of os.File. But this would be a pain, because they wouldn't need any of the implementation of an os.File; they would just be inheriting from it to satisfy the type system.
The example in the OP works because of a poorly-chosen method name. It is not at all clear what a Square's calculate method should return. Its area? Its perimeter? Its diagonal? If the method were named CalculateArea, which would be the idiomatic name for the single method in an interface named AreaCalculator, it would not be possible to confuse an AreaCalculator and a MathExpression.
Go uses implicit interfaces, it means that type implements interface if it has all functions required by interface. Note that you don't have to declare in code that type implements interface (as in Java).
Such language design have good and bad consequences:
type can implement interface by accident (this happened in your example). Actually it happens very rarely so IMO it is not a big problem.
without interface declaration in code you don't know which interfaces your type implements. This problem can be solved by using good IDEs.
you can easily create adapters and similar design patterns
you can easily create mocks
more readable code (type declaration is very simple in go)
One benefit of this approach is inversion of dependencies. In typical languages with static type systems, you have source level dependency from implementation to interface. Which means you can't deploy them separately. With implicit interfaces you have no source level dependency and implementation module can be deployed/developed/build without module containing interface. This gives you flexibility usually reserved for dynamic type systems.

Designing Go packages: when I should define methods on types?

Suppose that I have a type type T intand I want to define a logic to operate on this type.
What abstraction should I use and When ?
Defining a method on that type:
func (T t) someLogic() {
// ...
}
Defining a function:
func somelogic(T t) {
// ...
}
Some situations where you tend to use methods:
Mutating the receiver: Things that modify fields of the objects are often methods. It's less surprising to your users that x.Foo will modify X than that Foo(x) will.
Side effects through the receiver: Things are often methods on a type if they have side effects on/through the object in subtler ways, like writing to a network connection that's part of the struct, or writing via pointers or slices or so on in the struct.
Accessing private fields: In theory, anything within the same package can see unexported fields of an object, but more commonly, just the object's constructor and methods do. Having other things look at unexported fields is sort of like having C++ friends.
Necessary to satisfy an interface: Only methods can be part of interfaces, so you may need to make something a method to just satisfy an interface. For example, Peter Bourgon's Go intro defines type openWeatherMap as an empty struct with a method, rather than a function, just to satisfy the same weatherProvider interface as other implementations that aren't empty structs.
Test stubbing: As a special case of the above, sometimes interfaces help stub out objects for testing, so your stub implementations might have to be methods even if they have no state.
Some where you tend to use functions:
Constructors: func NewFoo(...) (*Foo) is a function, not a method. Go has no notion of a constructor, so that's how it has to be.
Running on interfaces or basic types: You can't add methods on interfaces or basic types (unless you use type to make them a new type). So, strings.Split and reflect.DeepEqual must be functions. Also, io.Copy has to be a function because it can't just define a method on Reader or Writer. Note that these don't declare a new type (e.g., strings.MyString) to get around the inability to do methods on basic types.
Moving functionality out of oversized types or packages: Sometimes a single type (think User or Page in some Web apps) accumulates a lot of functionality, and that hurts readability or organization or even causes structural problems (like if it becomes harder to avoid cyclic imports). Making a non-method out of a method that isn't mutating the receiver, accessing unexported fields, etc. might be a refactoring step towards moving its code "up" to a higher layer of the app or "over" to another type/package, or the standalone function is just the most natural long-term place for it. (Hat tip Steve Francia for including an example of this from hugo in a talk about his Go mistakes.)
Convenience "just use the defaults" functions: If your users might want a quick way to use "default" object values without explicitly creating an object, you can expose functions that do that, often with the same name as an object method. For instance, http.ListenAndServe() is a package-level function that makes a trivial http.Server and calls ListenAndServe on it.
Functions for passing behavior around: Sometimes you don't need to define a type and interface just to pass functionality around and a bare function is sufficient, as in http.HandleFunc() or template.Funcs() or for registering go vet checks and so on. Don't force it.
Functions if object-orientation would be forced: Say your main() or init() are cleaner if they call out to some helpers, or you have private functions that don't look at any object fields and never will. Again, don't feel like you have to force OO (à la type Application struct{...}) if, in your situation, you don't gain anything by it.
When in doubt, if something is part of your exported API and there's a natural choice of what type to attach it to, make it a method. However, don't warp your design (pulling concerns into your type or package that could be separate) just so something can be a method. Writers don't WriteJSON; it'd be hard to implement one if they did. Instead you have JSON functionality added to Writers via a function elsewhere, json.NewEncoder(w io.Writer).
If you're still unsure, first write so that the documentation reads clearly, then so that code reads naturally (o.Verb() or o.Attrib()), then go with what feels right without sweating over it too much, because often you can rearrange it later.
Use the method if you are manipulating internal secrets of your object
(T *t) func someLogic() {
t.mu.Lock()
...
}
Use the function if you are using the public interface of the object
func somelogic(T *t) {
t.DoThis()
t.DoThat()
}
if  you want to change T object, use
func (t *T) someLogic() {
// ...
}
if you donn't change T object and would like a origined-object way , use
func (t T) someLogic() {
// ...
}
but remeber that this will generate a temporay object T to call someLogic
if your like the way c language does, use
func somelogic(t T) {
t.DoThis()
t.DoThat()
}
or
func somelogic(t T) {
t.DoThis()
t.DoThat()
}
one more thing , the type is behide the var in golang.

Resources