config.Check does not recognize context.Context as context.Context interface - go

I am trying to execute types.Config.Check on github.com/OrlovEvgeny/go-mcache/mcache.go in order to extract the definitions and types in the Go file.
The problem is that the Check() method fails with:
cannot use ctx (variable of type context.Context) as context.Context value in argument to gcmap.NewGC: context.Context does not implement context.Context (wrong type for method Deadline)
have Deadline() (deadline time.Time, ok bool)
want Deadline() (deadline time. Time, ok bool)
The Context used in mcache library is quite standard, and is passed to NewGC():
func (mc *CacheDriver) initStore() (context.Context, context.CancelFunc) {
ctx, finish := context.WithCancel(context. Background())
mc.storage = safeMap.NewStorage()
mc.gc = gcmap.NewGC(ctx, mc.storage) // <-- The problem is here
return ctx, finish
}
I should also point out the library compiles successfully and works.
I have debugged the issue it ultimately the following line returns false (types/predicates. go:416):
return x.obj == y.obj
I have compared the two object, but they seem similar besides their token.Pos, which I guess it is the reason why it returns false.
Does anyone has any idea what am I missing here?
Thanks!

Related

Why return a func in Golang

I was looking into golang contexts recently, and found that the WithCancel() is implemented in an interesting way.
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
if parent == nil {
panic("cannot create context from nil parent")
}
c := newCancelCtx(parent)
propagateCancel(parent, &c)
return &c, func() { c.cancel(true, Canceled) }
}
WithCancel() returns a ctx, and also a func to cancel the very same context. Why is this done rather than introducing the .Cancel() as a func of the type itself, like
func (c *cancelCtx) Cancel() {
c.cancel(true, Canceled)
}
I understand using a func return type allows you to run a different func depending on runtime conditions, but there's no dynamic here - it's always the same func. Is this just because for the functional paradigm?
Reference: https://cs.opensource.google/go/go/+/master:src/context/context.go;l=232-239?q=context&ss=go%2Fgo
Not all contexts are cancel-able. You could argue that for those that aren't, the Cancel() method could be a no-op.
But then you would always have to call Cancel() whenever you work with context.Context because you don't (can't) know whether it truly needs cancelling. This would be unnecessary in a lot of cases, would make code slower (cancel functions are usually called deferred) and would bloat the code.
Also, the power of cancelling a context is for its creator only. The creator may choose to share this responsibility by passing / sharing the cancel function, but if doesn't, sharing the context alone does not allow (should not allow) cancelling it. If Cancel() would be part of context.Context, this restriction could not be enforced. For details, see Cancel context from child.
Interfaces–especially those widely used–should be small and a minimum, not containing all, rarely useful things.

idiomatic error and value order using Multiple Return Values in go

When creating a func that returns both an error and a result, which order should they be in? I've seen examples of both, and not sure where to look to confirm the idiomatic style.
should it be:
// a
func funcName(n int) (error, int) {}
// or b
func funcName(n int) (int, error) {}
As pointed out by #Gavin above in the comments :
If you look here, you will see By convention, errors are the last return value and have type error, a built-in interface.
As can be seen in the standard lib.

How to modify GORM DB pointer in function?

I have a REST API application written in Go, which uses GORM as ORM. During refactoring of some parts, I wanted to move some common operations to an external function ApplyToDBQuery(query *gorm.DB), which takes a pointer to the DB query and modifies it, so that the modified query can be used later.
Example usage:
query = shared.DB.Debug()
req.ApplytoDBQuery(query)
if query.find(&data).Error != nil {...}
func (this *MyCustomRequest) ApplyToDBQuery(query *gorm.DB) {
query.Limit(...)
query.Offset(...)
query.Where(...)
}
I thought, that since I'm passing a pointer to the function, the original query should've been modified, but nothing really happened to the original query.
I've also tried passing a pointer to pointer ApplyToDBQuery(query **gorm.DB), returning the modified pointer ApplyToDBQuery(query *gorm.DB) *gorm.DB and out of lack of ideas, even a combination of these two - ApplyToDBQuery(query **gorm.DB) *gorm.DB
Gorm object clone itself for every operation, therefore the original pointed value is never changed.
You should return the latest version of gorm.DB:
return query.Limit(...).Offset(...).Where(...)
Change the method receiver to
func (this *MyCustomRequest) ApplyToDBQuery(query *gorm.DB) *gorm.DB {
return query.Limit(...).
Offset(...).
Where(...)
}
then use it as:
query = req.ApplytoDBQuery(query)
if query.find(&data).Error != nil {...}
The reason is already pointed by #R3v4n
You should go with what the previous two answers recommend, but, if for some reason, you have to apply changes to the passed in pointer, you can still do it "manually".
query = shared.DB.Debug()
req.ApplytoDBQuery(query)
if query.find(&data).Error != nil {...}
func (r *MyCustomRequest) ApplyToDBQuery(query *gorm.DB) {
q := query.Limit(...).Offset(...).Where(...)
*query = *q
}
As a side note, it is generally discouraged to use receiver names like this and self, instead the preferred way is to use a short, let's say 1 to 3 letters, abbreviation of the type's name.
For example:
func (r *Request) AddCookie(c *Cookie)
func (c *Client) Get(url string) (resp *Response, err error)
func (srv *Server) ListenAndServe() error
Complementing #R3v4n answer:
Use chaining
Use db.Scopes for code reusage instead of usual func calls.
It can be like this:
query = shared.DB.Debug()
if query.Scopes(req.ApplyToDBQuery).find(&data).Error != nil {
// handle error
}
func (this *MyCustomRequest) ApplyToDBQuery(query *gorm.DB) *gorm.DB {
return query.Where(...).Limit(...).Offset(...)
}

Golang microservice middleware allow any type but be strict on endpoint

New to golang but what I'm trying to do is make my logging middleware generic e.g. allow any type and then call the method for the next layer.
So below us the loggingmiddleware package, where I want to be able to accept any type and print it out.
package loggingmiddleware
import (
"context"
"time"
gokitlogger "github.com/go-kit/kit/log"
)
type layer interface {
Run(context.Context, interface{}) (interface{}, error)
}
type LoggingMiddleware struct {
Logger gokitlogger.Logger
Layer layer
}
func (mw LoggingMiddleware) Run(ctx context.Context, i interface{}) (output interface{}, err error) {
defer func(begin time.Time) {
mw.Logger.Log(
"method", "name of method",
"input", i,
"output", output,
"err", err,
"took", time.Since(begin),
)
}(time.Now())
output, err = mw.Layer.Run(ctx, i)
return
}
However I want to be strict when calling the next method, if it needs to be string I want to set the type to be string rather than interface{}
In my example I want to make sure only a float64 type will be used as an argument
type mathServiceInterface interface {
Run(context.Context, float64) (float64, error)
}
type mathService struct{}
func (mathService) Run(_ context.Context, f float64) (float64, error) {
return f * f, nil
}
However with my current implementation I'm getting this error...
# github.com/jakelacey2012/blankit/blankit-ms/sqaure
./main.go:92: cannot use ms (type mathServiceInterface) as type loggingmiddleware.layer in field value:
mathServiceInterface does not implement loggingmiddleware.layer (wrong type for Run method)
have Run(context.Context, float64) (float64, error)
want Run(context.Context, interface {}) (interface {}, error)
./main.go:92: cannot use loggingmiddleware.LoggingMiddleware literal (type loggingmiddleware.LoggingMiddleware) as type mathServiceInterface in assignment:
loggingmiddleware.LoggingMiddleware does not implement mathServiceInterface (wrong type for Run method)
have Run(context.Context, interface {}) (interface {}, error)
want Run(context.Context, float64) (float64, error)
I understand the error, however I don't know whether my implementation is over complicating things because I don't know go.
I hope what I'm saying makes sense, I was unsure what to title this as so please feel free to edit it.
Also if you need more code to better explain please do let me know.
What's going to be calling these? At some point there is an actual consumer, and that consumer will (presumably, based on your code) be using an interface (either layer or an identical interface). If there's middleware, that interface will necessarily be as generic as the middleware - i.e., taking a interface{} as a parameter to Run. So making something downstream more specific (besides not compiling as you've seen) doesn't make any sense: the actual consumer won't see the more-specific interface, it will see Run(Context,interface{}) (interface{},error).
The error message says it all, for a type to implement an interface its methods must exactly match the methods the interface defines.
Sadly, this means that your system won't work as designed. You will either need to use interface{} and assert to the actual type at the end point, or you will need a separate interface (and logger function) for each type.

Is there idiomatic scoped semantics in golang?

I wonder if there is any idiomatic way to represent scoped semantics. By scoped I mean things like:
scoped mutex (oneliner instead of explicit Lock + deffered Unlock),
logging function (or any code block) entrance and exit,
measuring execution time.
Example code for first two bullets:
package main
import "log"
import "sync"
func Scoped(m *sync.Mutex) func() {
m.Lock()
return func() {
m.Unlock()
}
}
func Log(what string) func() {
log.Println(what, "started")
return func() {
log.Println(what, "done")
}
}
func main() {
defer Log("testing")()
m := &sync.Mutex{} // obviously mutex should be from other source in real life
defer Scoped(m)()
// use m
}
https://play.golang.org/p/33j-GrBWSq
Basically we need to make one function call just now (eg mutex lock), and one call should be postponed to defer (eg mutex unlock). I propose just returning unnamed function here, but it can be easily named (return struct with function field).
There is only one problem: user can forget to 'call' result of first call.
This code is (can be) idiomatic?
Take anonymous function as a scope:
func() {
Entrance()
defer Exit()
// anything you want to do in this scope
}()
Your proposed solution is already nice. You return a value of func type which you also have to call at the end of the defer.
You can avoid that (returning a func value), but there have to be 2 function calls, one that logs the start event and another one that logs the end event.
The alternative is to make a function call which produces the parameter value of the function that is deferred (rather than returning a function) which is evaluated with the defer statement, and this way it still can remain one line.
You can also try it on the Go Playground:
func start(s string) string {
fmt.Println("Started", s)
return s
}
func end(name string) {
fmt.Println("Ended", name)
}
func main() {
defer end(start("main"))
fmt.Println("Doing main's work...")
}
Output:
Started main
Doing main's work...
Ended main
I do not believe there is an idiomatic way to do this. I'm not sure why you'd want to either, is it really so bad to write
m.Lock()
defer m.Unlock()
?
I think question isn't relevant to Go idiomaticity, Seems it's generally better to reason about code when function behave identically either call. To keep state I'd better make an object and define function as method on that object. Means something like
type message string
func (foo message) Log(bar string){
if bar==nil{doSomethingSpecial()}
switch foo{
case something: doSomething()
...
case nil: doSomethingInitial()
default: doDefault()
}
log.Println(bar, "started")
foo=bar
}

Resources