Creating handlers from an interface - go

Let's say I have this interface
type Selecter interface {
Select(vars ...string) error
}
and I want to make handlers that pretty much just return JSON forms of that interface after it has called the Select function. Like this:
func MakeHandler(s Selecter) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
//... do some stuff to get vars ...
if err := s.Select(v1, v2); err != nil {
//... blah blah errors ...
}
b, err := json.Marshal(s)
if err != nil {
//... blah blah errors ...
}
w.Write(b)
}
}
So if CoolType is a Selecter I can do something like this
type CoolType struct {
CoolString string `json:"cool_string"`
CoolInt int `json:"cool_int"`
CoolBool bool `json:"cool_bool"`
}
func (c *CoolType) Select(vars ...string) error {
// fill up c using vars
return nil
}
// this looks kinda ugly to me too
fn := MakeHandler(CoolType{})
The underlying problem I have with this is that s is an interface and uses a pointer. This would make this not safe in goroutines since s could be modified between the calls to Select and the call to Marshal.
I really think this is the way I'd like to go about implementing this since it is fairly concise and easy for me to change, but I think I'm missing something. I could use reflect or change the Selecter interface to have Select return an interface{} instead since I don't particularly care what the type is. Then I'd just make a new copy of the type in every implementation of Select I guess. Or a mutex would work. Or perhaps the better way to do this would be to have all of my Selecter types just implement ServeHTTP and be an http.Handler.
Anyway I assume people have tried something like this and have come up with possibly more elegant solutions so I'd like to hear some ideas.

If you are afraid of mutations pass a copy of the value. To do it you probably have to change your interface to something like:
type Selecter interface {
Select(vars ...string) (Selecter, error)
}
And change your Select method to take a value receiver to fulfill the interface. It would be func (c CoolType) Select(vars ...string) (CoolType, error)
Then pass your s as a value instead of pointer and call Select like:
if s, err := s.Select(v1, v2); err != nil {
//... blah blah errors ...
}
You can argue that you lose information about the type, but you already lost it while passing the value as a Selecter interface.
But in general your implementation is good. My feeling is that in Go elegant is something different than in other languages. I'd say that in Go elegant is readable, maintainable and accurate - not bureaucracy and trying to protect you from yourself.

Related

Is there any way to handle nil pointer in Golang without using if/else?

I have this piece of code for example:
type MyStruct struct {
...
MyField *MyOtherStruct
...
}
type MyOtherStruct struct {
...
MyOtherField *string
...
}
// I have a fuction that receive MyOtherField as parameter
func MyFunc(myOtherField *string) {
...
}
// How can I avoid using if/else here
if MyStruct.MyField != nil {
MyFunc((*MyStruct.MyField).MyOtherField)
} else {
MyFunc(nil)
}
In my example, I have to use if else to handle whether MyStruct.MyField is nil or not. I would like to find a way to shorten my code.
I would like to find some way like MyFunc(MyStruct.MyField ? (*MyStruct.MyField).MyOtherField : nil) in JavaScript.
No, you cannot do what you used to do in JS. It is just syntactic sugar. But, there are some alternatives.
First, you can simply write:
if MyStruct.MyField != nil {
MyFunc(MyStruct.MyField.MyOtherField)
} else {
MyFunc(nil)
}
In some cases it may make sense to write getters that work with pointer receivers:
func (m *MyOtherStruct) GetOtherField() *OtherFieldType {
if m==nil {
return nil
}
return m.OtherField
}
Then you can do:
MyFunc(MyStruct.MyField.GetOtherField())
This is how gRPC generates Go models. It is not usually advisable, though. It hides subtle bugs. It is best to be explicit and check where you use it.
GoLang has no 'coalescing nil' operator or ternary conditions (by design, currently at least) but if you want to remove the else from your main flow you can extract it into a helper func.
I've illustrated this as a func with a *MyStruct receiver but it could equally exist as a standalone fun accepting a *MyStruct arg:
func (ms *MyStruct) getMyOtherFieldOrNil() *string {
if ms.MyField == nil {
return nil
}
return ms.MyField.MyOtherField
}
The name of the func makes it clear that a nil result is legitimate, to avoid any potential for confusion.
Then, when you need the MyField.MyOtherField or nil (when MyField is nil) you can use this in place of the if {} else {} construct:
ms := &MyStruct{}
// ...
MyFunc(ms.getMyOtherFieldOrNil())
Footnote
This is similar to Burak's answer but avoids the potential pitfalls of nil receivers which I believe are responsible for the "subtle bugs" mentioned. This slightly higher level helper func will simply panic if called on a nil *MyStruct receiver (as it should), but otherwise achieves much the same purpose.
You cannot avoid using if else. Even through you define a getter for MyStruct, there still if else inside. So I suggest that you should keep your original code for clear.
func TernaryFunc(statement bool, a, b interface{}) interface{} {
if statement {
return a
}
return b
}
MyFunc(TernaryFunc(MyStruct.MyField == nil, (*MyStruct.MyField).MyOtherField, nil).(string))
I'm not sure but try some things like this.

How to handle method with Nil Receiver?

type Product struct {
productName string
}
func (p *Product) GetProductName() string {
return p.productName
}
In Go, how should one typically handle a scenario where the receiver on a method is nil and the method logic itself yields no error (e.g a getter)?
Don't handle it, let it panic
Check for nil and return zero value if true
Check for nil and panic with meaningful message
Check for nil and enhance the method to return error on nil
Other
It really depends
I lean towards #1, but figure that while #3 is a bit verbose it could make debugging easier.
My thoughts are the calling code should be testing for nil and know what to do in such a scenario. That returning an error on a simple getter method is too verbose.
Don't handle it, let it panic
You can see examples in the go standard library. For example, in the net/http package, there is the following:
func (c *Client) Do(req *Request) (*Response, error) {
return c.do(req)
}
And, another example from encoding/json:
// Buffered returns a reader of the data remaining in the Decoder's
// buffer. The reader is valid until the next call to Decode.
func (dec *Decoder) Buffered() io.Reader {
return bytes.NewReader(dec.buf[dec.scanp:])
}

How do I use bson.SetBSON or bson.Raw?

Possibly related: How to use interface type as a model in mgo (Go)?
I have a struct like so:
type Game struct {
ID bson.ObjectId
Type string
Location string
Details interface{}
}
type FeudDetails struct {
...
}
type TriviaDetails struct {
...
}
type BingoDetails struct {
...
}
I want to use the Type field of Game to unserialize Details into a specific type (like an instance of FeudDetails or BingoDetails). It would still be an interface{} in Game, but then I could do this:
feudDetails, ok := game.Details.(FeudDetails)
if ok {
// we know this is a Feud game, and we have the details
feudDetails.Round++
}
The docs say that "it is possible to unmarshal or marshal values partially" using bson.Raw, but they don't provide any examples I've been able to find.
I've tried using:
func (game *Game) SetBSON(r bson.Raw) error {
err := r.Unserialize(game)
if err != nil {
return nil
}
games[game.Type].LoadDetails(game) // this calls a function based on the Type to
// create a concrete value for that game.
return nil
}
I get a (ahem) stack overflow here. I assume this is because r.Unserialize is recursively calling SetBSON.
My goal is to use standard unserializing on all fields except Details, and then be able to use game.Type to determine how to process Details. If I do something like this:
type GameDetails interface{}
type Game struct {
...
Details GameDetails
}
func (details *GameDetails) SetBSON(r bson.Raw) error {
// game isn't defined
games[game.Type].LoadDetails(r, details)
}
then how can I access the outer Type field to know which game type to unserialize it to?
I'll also accept the answer "you're doing it all wrong, and a better pattern in Go is XYZ..."
EDIT: I also tried deserializing normally, and then casting the interface{} version of Details using game.Details.(FeudDetails), but the conversion failed. I guess I can't do it that way because the underlying type after unserialization is not a FeudDetails but rather probably map[string]interface{}.
EDIT 2: I thought I'd be clever and pre-populate an object with the right types when retrieving from the database (game := Game{Details: FeudDetails: {}} prior to calling db...One(&game)) but my trickery did not work:
DEBU[Mar 31 22:19:09.442] Caching show gid=5e814448ef5b9858b7ff4e57
TRAC[Mar 31 22:19:09.442] Before database call dtype=main.FeudDetails
TRAC[Mar 31 22:19:09.446] After database call dtype=bson.M
Ignore Details during (un)marshalling
Change the definition of Game so bson doesn't try to do anything with the Details field:
type Game struct {
...
Details interface{} `json:"details" bson:"-"`
}
Unmarshal Details manually
func (game *Game) SetBSON(r bson.Raw) error {
// Unmarshall everything except Details
type tempGame Game
err := r.Unmarshal((*tempGame)(game)) // this is necessary to prevent recursion
if err != nil {
return err
}
// Get the raw data for Details
var d struct {
Details bson.Raw
}
if err := r.Unmarshal(&d); err != nil {
return err
}
gameType, ok := games[game.Type]
if ok {
// Use individual processing based on game Type
game.Details, err = gameType.LoadDetails(d.Details)
if err != nil {
return err
}
// fmt.Sprintf("%T", game.Details) => main.FeudDetails
}
return nil
}
Marshal Details manually
As far as I can tell, the only way to get bson to include Details after we told it to omit it in the original struct, is to create a whole other structure, copy the data over one by one, and use that type in GetBSON. It seems like there must be a better way.

Multiple values in single-value context

Due to error handling in Go, I often end up with multiple values functions. So far, the way I have managed this has been very messy and I am looking for best practices to write cleaner code.
Let's say I have the following function:
type Item struct {
Value int
Name string
}
func Get(value int) (Item, error) {
// some code
return item, nil
}
How can I assign a new variable to item.Value elegantly. Before introducing the error handling, my function just returned item and I could simply do this:
val := Get(1).Value
Now I do this:
item, _ := Get(1)
val := item.Value
Isn't there a way to access directly the first returned variable?
In case of a multi-value return function you can't refer to fields or methods of a specific value of the result when calling the function.
And if one of them is an error, it's there for a reason (which is the function might fail) and you should not bypass it because if you do, your subsequent code might also fail miserably (e.g. resulting in runtime panic).
However there might be situations where you know the code will not fail in any circumstances. In these cases you can provide a helper function (or method) which will discard the error (or raise a runtime panic if it still occurs).
This can be the case if you provide the input values for a function from code, and you know they work.
Great examples of this are the template and regexp packages: if you provide a valid template or regexp at compile time, you can be sure they can always be parsed without errors at runtime. For this reason the template package provides the Must(t *Template, err error) *Template function and the regexp package provides the MustCompile(str string) *Regexp function: they don't return errors because their intended use is where the input is guaranteed to be valid.
Examples:
// "text" is a valid template, parsing it will not fail
var t = template.Must(template.New("name").Parse("text"))
// `^[a-z]+\[[0-9]+\]$` is a valid regexp, always compiles
var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]$`)
Back to your case
IF you can be certain Get() will not produce error for certain input values, you can create a helper Must() function which would not return the error but raise a runtime panic if it still occurs:
func Must(i Item, err error) Item {
if err != nil {
panic(err)
}
return i
}
But you should not use this in all cases, just when you're sure it succeeds. Usage:
val := Must(Get(1)).Value
Go 1.18 generics update: Go 1.18 adds generics support, it is now possible to write a generic Must() function:
func Must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
This is available in github.com/icza/gog, as gog.Must() (disclosure: I'm the author).
Alternative / Simplification
You can even simplify it further if you incorporate the Get() call into your helper function, let's call it MustGet:
func MustGet(value int) Item {
i, err := Get(value)
if err != nil {
panic(err)
}
return i
}
Usage:
val := MustGet(1).Value
See some interesting / related questions:
How to pass multiple return values to a variadic function?
Return map like 'ok' in Golang on normal functions
Yes, there is.
Surprising, huh? You can get a specific value from a multiple return using a simple mute function:
package main
import "fmt"
import "strings"
func µ(a ...interface{}) []interface{} {
return a
}
type A struct {
B string
C func()(string)
}
func main() {
a := A {
B:strings.TrimSpace(µ(E())[1].(string)),
C:µ(G())[0].(func()(string)),
}
fmt.Printf ("%s says %s\n", a.B, a.C())
}
func E() (bool, string) {
return false, "F"
}
func G() (func()(string), bool) {
return func() string { return "Hello" }, true
}
https://play.golang.org/p/IwqmoKwVm-
Notice how you select the value number just like you would from a slice/array and then the type to get the actual value.
You can read more about the science behind that from this article. Credits to the author.
No, but that is a good thing since you should always handle your errors.
There are techniques that you can employ to defer error handling, see Errors are values by Rob Pike.
ew := &errWriter{w: fd}
ew.write(p0[a:b])
ew.write(p1[c:d])
ew.write(p2[e:f])
// and so on
if ew.err != nil {
return ew.err
}
In this example from the blog post he illustrates how you could create an errWriter type that defers error handling till you are done calling write.
No, you cannot directly access the first value.
I suppose a hack for this would be to return an array of values instead of "item" and "err", and then just do
item, _ := Get(1)[0]
but I would not recommend this.
How about this way?
package main
import (
"fmt"
"errors"
)
type Item struct {
Value int
Name string
}
var items []Item = []Item{{Value:0, Name:"zero"},
{Value:1, Name:"one"},
{Value:2, Name:"two"}}
func main() {
var err error
v := Get(3, &err).Value
if err != nil {
fmt.Println(err)
return
}
fmt.Println(v)
}
func Get(value int, err *error) Item {
if value > (len(items) - 1) {
*err = errors.New("error")
return Item{}
} else {
return items[value]
}
}
Here's a generic helper function with assumption checking:
func assumeNoError(value interface{}, err error) interface{} {
if err != nil {
panic("error encountered when none assumed:" + err.Error())
}
return value
}
Since this returns as an interface{}, you'll generally need to cast it back to your function's return type.
For example, the OP's example called Get(1), which returns (Item, error).
item := assumeNoError(Get(1)).(Item)
The trick that makes this possible: Multi-values returned from one function call can be passed in as multi-variable arguments to another function.
As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order.
This answer borrows heavily from existing answers, but none had provided a simple, generic solution of this form.

How to get the reflect.Type of an interface?

In order to determine whether a given type implements an interface using the reflect package, you need to pass a reflect.Type to reflect.Type.Implements(). How do you get one of those types?
As an example, trying to get the type of an uninitialized error (interface) type does not work (it panics when you to call Kind() on it)
var err error
fmt.Printf("%#v\n", reflect.TypeOf(err).Kind())
Do it like this:
var err error
t := reflect.TypeOf(&err).Elem()
Or in one line:
t := reflect.TypeOf((*error)(nil)).Elem()
Even Shaws response is correct, but brief. Some more details from the reflect.TypeOf method documentation:
// As interface types are only used for static typing, a common idiom to find
// the reflection Type for an interface type Foo is to use a *Foo value.
writerType := reflect.TypeOf((*io.Writer)(nil)).Elem()
fileType := reflect.TypeOf((*os.File)(nil)).Elem()
fmt.Println(fileType.Implements(writerType))
For googlers out there I just ran into the dreaded scannable dest type interface {} with >1 columns (XX) in result error.
Evan Shaw's answer did not work for me. Here is how I solved it. I am also using the lann/squirrel library, but you could easily take that out.
The solution really isn't that complicated, just knowing the magic combination of reflect calls to make.
The me.GetSqlx() function just returns an instance to *sqlx.DB
func (me *CommonRepo) Get(query sq.SelectBuilder, dest interface{}) error {
sqlst, args, err := query.ToSql()
if err != nil {
return err
}
// Do some reflection magic so that Sqlx doesn't hork on interface{}
v := reflect.ValueOf(dest)
return me.GetSqlx().Get(v.Interface(), sqlst, args...)
}
func (me *CommonRepo) Select(query sq.SelectBuilder, dest interface{}) error {
sqlst, args, err := query.ToSql()
if err != nil {
return err
}
// Do some reflection magic so that Sqlx doesn't hork on interface{}
v := reflect.ValueOf(dest)
return me.GetSqlx().Select(v.Interface(), sqlst, args...)
}
Then to invoke it you can do:
func (me *myCustomerRepo) Get(query sq.SelectBuilder) (rec Customer, err error) {
err = me.CommonRepo.Get(query, &rec)
return
}
func (me *myCustomerRepo) Select(query sq.SelectBuilder) (recs []Customer, err error) {
err = me.CommonRepo.Select(query, &recs)
return
}
This allows you to have strong types all over but have all the common logic in one place (CommonRepo in this example).

Resources