Thanks Ian for the thorough explanation - again I apologize for asking noob
questions :-).

The issue in this case was this error:

panic: value method github.com/shirou/gopsutil/process.Process.String
called using nil *Process pointer

which seems to be coming from the go runtime itself. Certainly the String
method of Process does not have a pointer receiver:

func (p Process) String() string {
        s, _ := json.Marshal(p)
        return string(s)
}

So it makes sense for the runtime to panic when we attempt to call it on a
nil pointer. I looked at the code for the fmt.Sprintf method as you
suggested and it seems to be doing the same thing as what my code is doing
- i.e. it catches the panic and then calls reflect to check if it is
because its a nil pointer. So i guess what feels hacky is really the way it
is supposed to be done in golang.

I wrote the following code to try to understand the behavior more
https://play.golang.org/p/kKWGCeacAEM
package main

import (
"fmt"
)

func type_function(a *int) {
fmt.Println("type_function: ", a == nil)
 }

func interface_function(a interface{}) {
fmt.Println("interface_function: ", a == nil)
}

func main() {
type_function(nil)           // true
interface_function(nil)   // true

var foo *int = nil
fmt.Println("is foo nil: ", foo == nil)
interface_function(foo)  // false ... ?
}

It seems to me that if a function accepts a pointer type - it is ok to
compare a pointer type against nil. But if a function accepts an interface
as an arg it is never safe to compare an interface against nil because from
inside the function you have no idea if the caller called with actual nil,
or a variable who's value is nil (this difference is very weird because
this is not how most languages behave - a variable is usually a full
substitute to the literal value it holds).

It seems to me that the compiler should at least warn when someone is
comparing an interface to nil (or maybe the linter should warn). It does
not seem that this could ever be what you actually want and it is always a
subtle bug just waiting to bite.

Thanks
Michael.


On Wednesday, 9 May 2018, Ian Lance Taylor <i...@golang.org> wrote:

> On Tue, May 8, 2018 at 7:19 AM, Michael Cohen <scude...@gmail.com> wrote:
> >
> > Well no - the error I get is that I am attempting to call String()
> method on
> > a null receiver - so the caller just passed me a regular nil object. The
> > issue is that I am trying to make a generic polymorphic function which
> > should be able to handle whatever is thrown at it - so I guess reflect is
> > necessary.
> >
> >  I think I am supposed to detect the null receiver before calling
> String()
> > on it. I ended up using this little utility:
> >
> > https://stackoverflow.com/questions/13476349/check-for-nil-a
> nd-nil-interface-in-go
> >
> > func isNil(a interface{}) bool {
> >   defer func() { recover() }()
> >   return a == nil || reflect.ValueOf(a).IsNil()
> > }
> >
> >
> > But this feels really hacky when I really just want to say if value !=
> nil {
> > ....} .
>
> I think there may be some confusion here.  Go doesn't have a "regular
> nil object."  Specific types can be `nil`.  In particular, pointer
> types can be `nil`.
>
> When a type implements a `String` method it is possible to call that
> method with a `nil` pointer.  In general it is possible to call any
> method with a `nil` pointer.  That is not an error.
>
> Some specific implementations of a `String` method may panic when
> called with a `nil` pointer.  For better or for worse, the fmt package
> has special handling for this.
>
> What this means is that unless you have some special knowledge of the
> type you are working with, you should not check for `nil` before
> calling the `String` method.  For some types the `String` method will
> correctly handle `nil`.  If you have types with a `String` method that
> does not correctly handle `nil`, then it's worth pondering why and how
> you got a `nil` pointer for this type in the first place.  But if you
> can reasonably have a `nil` pointer, and can reasonably expect that
> the `String` method will panic in that case, then what you should do
> is call `fmt.Sprint(v)`.  That will do the right thing whether v's
> `String` method handles `nil` or not.
>
> Ian
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to