Motivation
I have custom error type named CustomError and I want to write a method that parses any type of error into my error structure. So I wrote parse method to show you. I will use the parse method on any function that returns error interface. So all errors will be structured with my type.
Problem
When I use parse method with nil value to return error interface, the returning error is not nil. Code is below. First test succeeded but second did not.
const (
UnHandledError = "UnHandledError"
CircuitBreakerError = "CircuitBreakerError"
)
type CustomErrorType struct {
Key string
Message string
Status int
}
func (c *CustomErrorType) Error() string {
return "Custom error message"
}
func parse(err error) *CustomErrorType {
if err == nil {
return nil
}
if e, ok := err.(*CustomErrorType); ok {
return e
}
if e, ok := err.(hystrix.CircuitError); ok {
return &CustomErrorType{CircuitBreakerError, e.Message, http.StatusTooManyRequests}
}
return &CustomErrorType{UnHandledError, err.Error(), http.StatusInternalServerError}
}
func TestParse_it_should_return_nil_when_error_is_nil(t *testing.T) {
result := parse(nil)
if result != nil {
t.Error("result is not nil")
}
}
func TestParse_it_should_return_nil_when_error_is_nil_2(t *testing.T) {
aFunc := func() error {
return parse(nil)
}
result := aFunc()
if result != nil {
t.Error("result is not nil")
}
}
Can you explain what am I missing or what is wrong?
This is an instance of a common "problem" of go's interfaces that is caused by the actual implementation of interfaces under the hood: an interface containing a nil pointer is not-nil.
it is described in go's faq with an example that resembles your situation with the error interface: Why is my nil error value not equal to nil?
Under the covers, interfaces are implemented as two elements, a type T and a value V. V is a concrete value such as an int, struct or pointer, never an interface itself, and has type T.
...
An interface value is nil only if the V and T are both unset, (T=nil, V is not set), In particular, a nil interface will always hold a nil type. If we store a nil pointer of type *int inside an interface value, the inner type will be *int regardless of the value of the pointer: (T=*int, V=nil). Such an interface value will therefore be non-nil even when the pointer value V inside is nil.
This situation can be confusing, and arises when a nil value is stored inside an interface value such as an error return:
func returnsError() error {
var p *MyError = nil
if bad() {
p = ErrBad
}
return p // Will always return a non-nil error.
}
this example is similar to what is happening in your code when you do:
aFunc := func() error {
return parse(nil)
}
parse() returns *CustomErrorType, but the function just error making the value returned an interface that contains a type and a nil value: (T=*CustomErrorType, V=nil) that in turn evaluates to not-nil.
the faq then goes on providing explanation and showing a "correct" example:
If all goes well, the function returns a nil p, so the return value is an error interface value holding (T=*MyError, V=nil). This means that if the caller compares the returned error to nil, it will always look as if there was an error even if nothing bad happened. To return a proper nil error to the caller, the function must return an explicit nil:
func returnsError() error {
if bad() {
return ErrBad
}
return nil
}
the behavior can also be observed in your example adding a
fmt.Printf("%#v\n", result)
to print result's value:
(*e.CustomErrorType)(nil)
if we change parse() return type to just error it will print:
<nil>
Related
I have the concept of Context which is a map that can hold any structure. Basically, I want to create a generic getter that adddressably 'populates' the destination interface (similarly to how json decoding works).
Here's an example of how I want this to work:
type Context map[string]interface{}
// Random struct that will be saved in the context
type Step struct {
Name string
}
func main() {
stepA := &Step{Name: "Cool Name"}
c := Context{}
c["stepA"] = stepA
var stepB *Step
err := c.Get("stepA", stepB)
if err != nil {
panic(err)
}
fmt.Println(stepB.Name) // Cool Name
stepB.Name = "CoolName2"
fmt.Println(stepA.Name) // I want to say: CoolName2
}
func (c Context) Get(stepId string, dest interface{}) error {
context, ok := c[stepId]
if !ok {
return nil
}
destinationValue := reflect.ValueOf(dest)
contextValue := reflect.ValueOf(context)
destinationValue.Set(contextValue) // Errors here
return nil
}
I leaned towards using reflect, but maybe I don't need it? - so opened to other suggestions (except for generics as that complicates other matters) I'm getting the following error with the above:
panic: reflect: reflect.Value.Set using unaddressable value
You can test it here.
The argument passed to Get must be a pointer type whose element type is identical to the type in the context map. So if the value in the context map is of type *Step, then the argument's type must be **Step. Also the passed in argument cannot be nil, it can be a pointer to nil, but it itself cannot be nil.
So in your case you should do:
var stepB *Step
err := c.Get("stepA", &stepB) // pass pointer-to-pointer
if err != nil {
panic(err)
}
And the Get method, fixed up a bit:
func (c Context) Get(stepId string, dest interface{}) error {
context, ok := c[stepId]
if !ok {
return nil
}
dv := reflect.ValueOf(dest)
if dv.Kind() != reflect.Ptr || dv.IsNil() {
return errors.New("dest must be non-nil pointer")
}
dv = dv.Elem()
cv := reflect.ValueOf(context)
if dv.Type() != cv.Type() {
return errors.New("dest type does not match context value type")
}
dv.Set(cv)
return nil
}
https://go.dev/play/p/OECttqp1aVg
Consider following simplified example:
package main
import (
"fmt"
)
type IMessenger interface {
Message()
}
type TMyMessenger struct {
}
func (m TMyMessenger) Message() {}
func MessengerFactory() IMessenger {
return getInternalMessengerVariant()
}
func getInternalMessengerVariant() *TMyMessenger {
return nil
}
func main() {
e := MessengerFactory()
fmt.Println(" e == nil", e == nil) // *TMyMessenger(nil)
if e != nil {
e.Message()
}
}
And it's output:
e == nil false
panic: runtime error: invalid memory address or nil pointer dereference
Question 1:
Is there an idiomatic Go way to check if e points to a nil pointer?
Preferably an inline snippet.
Basically make the e != nil to be false even in the example case.
What I have considered:
There would not be this issue if getInternalMessengerVariant() would return Interface type instead of concrete pointer, but it requires refactor and may still go undetected and yield itself as a panic at runtime (if e != nil).
func getInternalMessengerVariant() IMessenger {
return nil
}
Rewrite MessengerFactory() to intercept the internal returns:
func MessengerFactory() IMessenger {
if m := getInternalMessengerVariant(); m != nil {
return m
}
return nil
}
Be very specific on type checking, but what if there are many types:
if e != nil && e != (*TMyMessenger)(nil) {
e.Message()
}
This problem exists whenever you return an interface from a function: if the interface contains a typed nil-pointer, interface itself is not nil. There is no easy way to check that.
A good way to deal with this is to return a nil for the interface:
func MessengerFactory() IMessenger {
x:= getInternalMessengerVariant()
if x==nil {
return nil
}
return x
}
Then you will not need to check if the return value points to a nil pointer.
Burak Serdar explains well in his answer why if x == nil returns false for you.
But that is not the reason why you get the panic.
Go is happy to invoke a receiver function on a nil pointer, as long as the receiver doesn't dereference the pointer.
This does not panic:
type TMyMessenger struct {
}
func (m *TMyMessenger) Message() {}
func main() {
var t *TMyMessenger = nil
t.Message()
}
and that's because you don't dereference the pointer m inside the Message receiver function.
Your example only panics because you have defined the receiver function m on the type TMyMessenger (not a pointer). Because of that, Go will have to dereference the nil pointer to TMyMessenger that is inside the IMessenger interface value, in order to invoke the receiver function.
If you change one line in your code, it will no longer panic:
func (m *TMyMessenger) Message() {}
(change (m TMyMessenger) to (m *TMyMessenger))
I thought I have asserted (as far as I've learnt Go), but I keep getting this error
cannot use readBack["SomePIN"] (type interface {}) as type string in argument to c.String: need type assertion
Here is my code (this snippet is from a Request Handler function and I'm using Echo Web framework and Tiedot NoSQL database)
// To get query result document, simply
// read it [as stated in the Tiedot readme.md]
for id := range queryResult {
readBack, err := aCollection.Read(id)
if err != nil {
panic(err)
}
if readBack["OtherID"] == otherID {
if _, ok := readBack["SomePIN"].(string); ok {
return c.String(http.StatusOK, readBack["SomePIN"])
}
}
}
You are asserting readBack["SomePIN"] as a string - in the if statement. That doesn't make any change to readBack["SomePIN"], however - it's still an interface{}. In Go, nothing ever changes type. Here's what will work:
for id := range queryResult {
readBack, err := aCollection.Read(id)
if err != nil {
panic(err)
}
if readBack["OtherID"] == otherID {
if somePIN, ok := readBack["SomePIN"].(string); ok {
return c.String(http.StatusOK, somePIN)
}
}
}
You were tossing the string value from your type assertion, but you want it. So keep it, as somePIN, and then use it.
Final note - using the value, ok = interfaceVal.(type) syntax is a good practice. If interfaceVal turns out to be a non-string, you'll get value = "" and ok = false. If you eliminate the ok value from the type assertion and interfaceVal is a non-string, the program will panic.
It looks like your converting to a concrete type and throwing away the conversion, I think this should work:
if somePinString, ok := readBack["SomePIN"].(string); ok {
return c.String(http.StatusOK, somePinString)
}
If I have a struct with a function like this:
type data struct{}
func (d *data) Foo() (string, error) {
return "", errors.New("bad")
}
And I call .Foo in a template, like this:
{{ .Foo }}
I get an error:
error calling Foo: bad
This is in line with the documentation for text/template:
The name of a niladic method of the data, preceded by a period, such as
.Method The result is the value of invoking the method with dot as the receiver, dot.Method(). Such a method must have one return
value (of any type) or two return values, the second of which is an
error. If it has two and the returned error is non-nil, execution
terminates and an error is returned to the caller as the value of
Execute.
Can I define a function to "catch" that error and return some default message, instead of halting execution? For example:
func Catch(val string, err error) string {
if err != nil {
return "[render error]"
} else {
return val
}
}
Then:
map := template.FuncMap{"catch": Catch}
tpl := template.Must(template.New("t").Funcs(map).Parse(`
{{ .Foo | catch }}
`))
b := new(bytes.Buffer)
err := tpl.Execute(b, &data{})
That currently renders an error - is there a way to get it to work?
Here's my very hacky answer, which Calls a method on the internal struct, and then returns "redacted" if you get back a specific error.
// Call calls the given method name on a Message. If the result is
// a PermissionDenied error, return the string "[redacted]" and no error.
//
// This should be used by templates to redact methods. It would be nicer to
// just call the Message directly, but returning an error from a niladic method
// immediately halts template execution, so we need this wrapper around the
// function behavior.
func (r *RedactedMessage) Call(mname string) (interface{}, error) {
if mname == "" {
return nil, errors.New("Call() with empty string")
}
for _, char := range mname {
if !unicode.IsUpper(char) {
return nil, errors.New("Cannot call private method")
}
// only check first character
break
}
t := reflect.ValueOf(r.mv)
m := t.MethodByName(mname)
if !m.IsValid() {
return nil, fmt.Errorf("Invalid method: %s", mname)
}
vals := m.Call([]reflect.Value{})
if len(vals) != 2 {
return nil, fmt.Errorf("Expected to get two values back, got %d", len(vals))
}
if vals[1].IsNil() {
return vals[0].Interface(), nil
}
if reflect.DeepEqual(vals[1].Interface(), config.PermissionDenied) {
return "redacted", nil
}
return nil, vals[1].Interface().(error)
}
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.