Handle pointer to nil pointer in Go - go

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

Related

Go - Enforce that an interface is only satisfied by types with a pointer receiver on a method?

I'm doing some experimentation with type parameters to come up with a generic way of wiring up structs that generate a response to JSON HTTP requests.
The Method interface which the structs must implement has a SetParams method. This will work as expected as long as the implementation uses a pointer receiver.
My question: Is there any way of making this a compile time error if SetParams has a value receiver?
Here is an example demonstrating the problem with a SetParams that has a value receiver:
package main
import (
"encoding/json"
"fmt"
"log"
)
type PingParams struct {
Name string
}
type PingResponse struct {
Message string
}
func (p PingParams) Greeting() string {
if p.Name != "" {
return fmt.Sprintf("Hello, %s", p.Name)
}
return fmt.Sprintf("Hello, nobody!")
}
type GoodPing struct {
Params PingParams
}
// SetParams has a pointer receiver.
func (m *GoodPing) SetParams(p PingParams) {
fmt.Printf("assign %v with pointer receiver, Good!\n", p)
m.Params = p
}
func (m GoodPing) Run() (*PingResponse, error) {
return &PingResponse{Message: fmt.Sprintf("%T %s", m, m.Params.Greeting())}, nil
}
type BadPing struct {
Params PingParams
}
// SetParams has a value receiver.
func (m BadPing) SetParams(p PingParams) {
fmt.Printf("assign %v with value receiver, Bad!\n", p)
m.Params = p
}
func (m BadPing) Run() (*PingResponse, error) {
return &PingResponse{Message: fmt.Sprintf("%T %s", m, m.Params.Greeting())}, nil
}
type Method[M, RQ, RS any] interface {
// Run builds the RPC result.
Run() (*RS, error)
// SetParams is intended to set the request parameters in the struct implementing the RPC method.
// This then allows the request parameters to be easily available to all methods of the Method struct.
// The method MUST have a pointer receiver. This is NOT enforced at compile time.
SetParams(p RQ)
// The following line requires the implementing type is a pointer to M.
*M
// https://stackoverflow.com/a/72090807
}
func HandlerMethod[M, RQ, RS any, T Method[M, RQ, RS]](in json.RawMessage) (*RS, error) {
// A real implementation of this would return a func for wiring into a request router
var req RQ
err := json.Unmarshal(in, &req)
if err != nil {
return nil, err
}
var m T = new(M)
m.SetParams(req)
return m.Run()
}
func main() {
payload := []byte(`{"Name": "Mark"}`)
bad, err := HandlerMethod[BadPing, PingParams, PingResponse](payload)
if err != nil {
log.Fatal(err)
}
fmt.Println(bad.Message)
good, err := HandlerMethod[GoodPing, PingParams, PingResponse](payload)
if err != nil {
log.Fatal(err)
}
fmt.Println(good.Message)
}
https://go.dev/play/p/Eii8ADkmDxE
You can't do that.
When in your code you do this:
var m T = new(M)
even if T's type set includes only *M as a type term, *M's method set includes methods declared on M. The compiler can't check for you how the method ends up in *M's method set.
It is your responsibility when declaring the method SetParam on BadPing to make sure that the method doesn't attempt to unfruitfully modify the receiver.

go type-switch how to deal with point to nil

like this, if msg point to null value, how to deal with it in clean code
func test(a SomeType) {
switch msg := a.(type) {
case *type1:
dosomething1(a)
case *type2:
dosomething2(a)
case *type3:
dosomething3(a)
default:
do()
}
the main func may be this
func main() {
var b_ptr *stTest
aa := interface{}(b)
test(aa)
}
type test struct {
c int
d string
}
b_ptr is a pointer, but it point to nil, i want to judge it in test func
if i use b_ptr in test func, eg: print a.c or a.d, it will crash.
i do it by this way. do if(), everywhere use a, but it too stupid.
func test(a SomeType) {
switch msg := a.(type) {
case *type1:
if msg == nil {
return
}
dosomething1(a)
case *type2:
if msg == nil {
return
}
dosomething2(a)
case *type3:
if msg == nil {
return
}
dosomething3(a)
default:
do()
}
Generally this ought to be considered a problem with the caller, and therefore it should be the caller's job to deal with the fallout. Passing around non-nil interfaces that hold nil values is bad practice unless it's intentional/expected.
If you can't avoid the non-nil interface with nil-pointer however, then you can use reflect to check if the underlying value is nil.
func test(a SomeType) {
if rv := reflect.ValueOf(a); !rv.IsValid() || rv.IsNil() {
return
}
switch msg := a.(type) {
case *type1:
dosomething1(a)
case *type2:
dosomething2(a)
case *type3:
dosomething3(a)
default:
do()
}
}

Confusion with interfaces

I'm writing a parser in Go and I have a following code for ast construction:
type NODE interface {
GetPosition() (int, int)
}
type EXPRESSION_NODE interface {
NODE
expressionNode()
}
// binary node
type BINARY_EXPRESSION struct {
Operator string
Left, Right EXPRESSION_NODE
Position
}
// implementing the EXPRESSION_NODE interface for BINARY_EXPRESSION
func (s BINARY_EXPRESSION) expressionNode()
func (s BINARY_EXPRESSION) GetPosition() (int, int) { return s.Line, s.Column }
So I have an interface EXPRESSION_NODE and BINARY_EXPRESSION struct and the struct implements all the interface methods
And here is my confusion:
func (self *Parser) ParseBinaryExpression(
operators []string,
parser ExpressionParser,
) (*EXPRESSION_NODE, error) {
self.SetPosition()
result, err := parser()
if err != nil {
return nil, ChainErrs(self.Err(BINARY_EXPRESSION_ERROR), err)
}
for Includes(operators, self.stream.Peek().Literal) {
operator := self.stream.Next().Literal
right, err := parser()
if err != nil {
return nil, ChainErrs(self.Err(BINARY_EXPRESSION_ERROR), err)
//ERROR: cannot use &(BINARY_EXPRESSION literal) (value of type *BINARY_EXPRESSION) as *EXPRESSION_NODE value in assignment
result = &BINARY_EXPRESSION{operator, result, right, self.position}
}
}
return result, nil
}
So this line
result = &BINARY_EXPRESSION{operator, result, right, self.position}
gives me the following error: cannot use &(BINARY_EXPRESSION literal) (value of type *BINARY_EXPRESSION) as *EXPRESSION_NODE value in assignment
So when I do
var a EXPRESSION_NODE = &BINARY_EXPRESSION{}
without pointer everything seems ok, but with pointers...
And the thing is I actually need to return *EXPRESSION_NODE from my function
[The code in your question is partial, and thus the following is a sketch, not intended as full working code]
Generally, you almost certainly never want to use a pointer to an interface. What you want instead is a pointer to your type to implement an interface.
First, make sure the pointer to your type implements the interface:
type BINARY_EXPRESSION struct {
Operator string
Left, Right EXPRESSION_NODE
Position
}
// Note that pointer receivers
func (s *BINARY_EXPRESSION) expressionNode()
func (s *BINARY_EXPRESSION) GetPosition() (int, int) { return s.Line, s.Column }
And then your parse function would be something like:
func (self *Parser) ParseBinaryExpression(
operators []string,
parser ExpressionParser,
) (EXPRESSION_NODE, error) {
// ... stuff ...
result = &BINARY_EXPRESSION{operator, result, right, self.position}
return result, nil
}
I recommend you learn more about Go interfaces and how to define methods that implement them:
https://golang.org/doc/faq#methods_on_values_or_pointers
https://tour.golang.org/methods/4
https://golangbyexample.com/pointer-vs-value-receiver-method-golang/

How to detect custom errors

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>

Implementing Redigo Scanner interface on a struct's field

I have a struct that looks like this:
type authEnum int
const (
never authEnum = iota
sometimes
always
)
type Attrs struct {
Secret string `redis:"secret"`
RequireSecret authEnum `redis:"requireSecret"`
UserID string `redis:"userId"`
}
func (e *authEnum) RedisScan(src interface{}) error {
// This never gets called!
if e == nil {
return fmt.Errorf("nil pointer")
}
switch src := src.(type) {
case string:
if src == "false" || src == "never" {
*e = never
} else if src == "sometimes" {
*e = sometimes
} else { // "always" or "true"
*e = always
}
default:
return fmt.Errorf("cannot convert authEnum from %T to %T", src, e)
}
return nil
}
func getAttributes(ctx *AppContext, hash string) (*Attrs, error) {
rc := ctx.RedisPool.Get()
values, err := redis.Values(rc.Do("HGETALL", "redishash"))
rc.Close()
if err != nil {
return nil, err
}
attrs := Attrs{}
redis.ScanStruct(values, &attrs)
return &attrs, nil
}
How do I implement the Scanner interface on the RequireSecret attribute to parse an authEnum type out of "never", "sometimes" or "always" redis hash values?
How do I calculate the value and assign it to the authEnum?
In my code example RedisScan never gets called.
You don't implement interfaces on fields, but rather on types.
You can make your authEnum type satisfy the interface, simply by creating a method with the signature RedisScan(src interface{}) error on that type.
To assign to the receiver, you need to receive a pointer. Then you can assign to it as so:
func (e *authEnum) RedisScan(src interface{}) error {
var value authEnum
// Logic here to convert src to value
*e = value
}
Implement the method on a pointer receiver. Redis bulk strings are represented as []byte, not string:
func (e *authEnum) RedisScan(src interface{}) error {
b, ok := src.([]byte)
if !ok {
return fmt.Errorf("cannot convert authEnum from %T to %T", src, b)
}
switch string(b) {
case "false", "never":
*e = never
case "sometimes":
*e = sometimes
default:
*e = always
}
return nil
}
Always check and handle errors. The error returned from ScanStruct reports the type problem.
There's no need to check for nil pointer to the struct member. If the argument to ScanStruct is nil, then Redigo will panic well before the RedisScan method is called.

Resources