Why can I call methods on nil pointers?

9,125 views
Skip to first unread message

beatgammit

unread,
Sep 11, 2012, 8:55:11 PM9/11/12
to golan...@googlegroups.com
Code example:

http://play.golang.org/p/0RQNesP2IC

I understand that struct data is separated from struct methods, but I couldn't think of any practical reasons where this would be a good idea and not indicate a bug. It seems like it could cause strange problems or really bad style (using structs as a poor-man's package).

I was about to file a bug report until I read a thread that gave the above example claiming that it's allowed.

Thanks!

Ian Lance Taylor

unread,
Sep 11, 2012, 9:02:50 PM9/11/12
to beatgammit, golan...@googlegroups.com
Why disallow it? As you can see, it works fine. Of course, you can't
dereference a nil receiver, but so what?

For an example of an implementation that has methods on value that do
not use the value, see encoding/binary. (Although in that case the
types are struct{}, not pointer types.)

Ian

beatgammit

unread,
Sep 11, 2012, 9:33:49 PM9/11/12
to golan...@googlegroups.com, beatgammit
It took me a minute to debug a nil pointer dereference, and this was the cause. It didn't too long because there was a stack trace, but it did take a minute to convince myself that it was possible.

It just seems like it could cause significant confusion.

beatgammit

unread,
Sep 11, 2012, 9:35:55 PM9/11/12
to golan...@googlegroups.com, beatgammit
Also, Go does tell you where a go routine was created from, so stack traces are still useful if you run it in a goroutine.


On Tuesday, September 11, 2012 7:03:03 PM UTC-6, Ian Lance Taylor wrote:

Andrew Gerrand

unread,
Sep 11, 2012, 11:36:52 PM9/11/12
to beatgammit, golan...@googlegroups.com
> I understand that struct data is separated from struct methods,

Then it should be obvious why it doesn't matter what the value is.
Methods are orthogonal to the underlying data. One might similarly ask
"Why can I pass a nil pointer to a function?" The answer is: because
pointers can be nil.

On 12 September 2012 11:33, beatgammit <beatg...@gmail.com> wrote:
> It just seems like it could cause significant confusion.

To me, it would be more confusing otherwise. It would be inconsistent.

It would also be difficult to implement. To prevent calling of methods
on nil pointers you would need to guarantee at *compile time* that a
variable of type *T (for any T) is not nil whenever a method call is
made. How do you propose to do that reliably? What kind of error
messages would you see when such a compile error occurs?

Think it through, and the you'll see that the only sane way to deal
with this is to remove nil pointers from the language. Go is not that
kind of language.

There are plenty of cases where it is useful to call methods on nil
pointers (or maps, slices, and channels).

For instance, types that implement fmt.Stringer can choose how they
are formatted when they are nil. (Try running "godoc -src net
String".)

Another example is in generated protobuf code, where you can use
getter methods to traverse structures that don't exist in memory and
still get the correct default values.

Andrew

Nigel Tao

unread,
Sep 11, 2012, 11:40:04 PM9/11/12
to Andrew Gerrand, beatgammit, golan...@googlegroups.com
On 12 September 2012 13:36, Andrew Gerrand <a...@golang.org> wrote:
> There are plenty of cases where it is useful to call methods on nil
> pointers (or maps, slices, and channels).

Yet another example is an Options struct where passing a nil *Options
means to use the default value:
http://code.google.com/p/leveldb-go/source/browse/leveldb/db/options.go

Rémy Oudompheng

unread,
Sep 11, 2012, 11:56:45 PM9/11/12
to beatgammit, golan...@googlegroups.com
On 2012/9/12 beatgammit <beatg...@gmail.com> wrote:
> It took me a minute to debug a nil pointer dereference, and this was the
> cause. It didn't too long because there was a stack trace, but it did take a
> minute to convince myself that it was possible.
>
> It just seems like it could cause significant confusion.

It is usual to define methods on pointers rather than values (even if
they don't modify it) to avoid calling a pointer method automatically
generated from a value method. If you have a nil pointer dereference
in a pointer method, you can check your argument before using it.

Method receivers are just ordinary arguments and there is no reason
they cannot be nil pointers, nil maps, nil channels or nil slices. The
sort.Interface interface is implemented by nil slices and we certainly
want to sort nil slices.

As a side note, C++ also allows calling methods on nil pointers, so it
is not a Go weirdness.

#include <vector>

class A {
public:
static std::vector<A*> them;

void add() {
them.push_back(this);
}
};

std::vector<A*> A::them;

int main() {
A* p = new A();
p->add();

p = NULL;
p->add();
}

Rémy.

unread,
Sep 12, 2012, 2:15:21 AM9/12/12
to golan...@googlegroups.com
On Wednesday, September 12, 2012 2:55:11 AM UTC+2, beatgammit wrote:
Code example:

http://play.golang.org/p/0RQNesP2IC

I understand that struct data is separated from struct methods, but I couldn't think of any practical reasons where this would be a good idea and not indicate a bug. It seems like it could cause strange problems or really bad style (using structs as a poor-man's package).

In C++/Java and similar object-oriented languages: The type is always behind the object.  object -> type

In Go: The type is next to the object.  interface = (type, object)

Singletons in C++ do not actually need an instance of the class, but an instance has to be created because of the rule that the type is behind a pointer.

roger peppe

unread,
Sep 12, 2012, 4:56:35 AM9/12/12
to Ian Lance Taylor, beatgammit, golan...@googlegroups.com
This thread reminded me of something I've sometimes
wondered.

If a value method is called on a pointer type that happens to be
nil we currently crash. How about passing it the zero instance of the value
instead?

These crashes are always annoying, particularly as the
crash happens in an auto-generated function with
no source-code location.

Then it would be possible to define a String method
which would work on every possible receiver, for example,
something that's useful when a type is used both as a
value and a pointer.

Andrew Gerrand

unread,
Sep 12, 2012, 5:34:52 AM9/12/12
to roger peppe, beatgammit, Ian Lance Taylor, golan...@googlegroups.com

That seems to me like a programming mistake, and the philosophy is to panic on programmer error (most likely).

Have you encountered this scenario in real code? I'm curious for more context.

Andrew

--


Peter

unread,
Sep 12, 2012, 5:37:17 AM9/12/12
to golan...@googlegroups.com, Ian Lance Taylor, beatgammit
That sounds potentially confusing. 

Would you really want this to behave differently?

roger peppe

unread,
Sep 12, 2012, 5:48:59 AM9/12/12
to Peter, golan...@googlegroups.com, Ian Lance Taylor, beatgammit
On 12 September 2012 10:37, Peter <peter.a...@gmail.com> wrote:
> That sounds potentially confusing.
>
> Would you really want this to behave differently?
> http://play.golang.org/p/e_nV5EfPdX

no. but this would print an empty string: http://play.golang.org/p/04BFl6o71B

roger peppe

unread,
Sep 12, 2012, 6:05:04 AM9/12/12
to Andrew Gerrand, beatgammit, Ian Lance Taylor, golan...@googlegroups.com
On 12 September 2012 10:34, Andrew Gerrand <a...@google.com> wrote:
> That seems to me like a programming mistake, and the philosophy is to panic
> on programmer error (most likely).
>
> Have you encountered this scenario in real code? I'm curious for more
> context.

I've seen this issue when I've got both pointer methods
and value methods on a type, and code that uses that
type by value and sometimes by pointer.

Because we're passing it around by value, it makes
sense to have the String method on the value type
(that way it can be used on both pointers and values),
but that means we can't define String for all values.

You can make a Stringer interface value from a nil
pointer (due to the usual method semantics) but
you can never call String on it without crashing.
That seems a little odd, hence my musing about
a possible general fix.

(BTW I am aware of the special hack in fmt that deals
with this kind of nil pointer dereference - this mitigated
most of the pain I was having previously).

Jan Mercl

unread,
Sep 12, 2012, 6:25:01 AM9/12/12
to roger peppe, Ian Lance Taylor, beatgammit, golan...@googlegroups.com
On Wed, Sep 12, 2012 at 10:56 AM, roger peppe <rogp...@gmail.com> wrote:

I see the benefits but I am not comfortable with the exceptional behavior.

Given:
var p *t
var value, zero t
// ...

Then this somewhere later:
value = *p

doesn't equal:
value = zero

if p == nil and it panics instead. Now in the case of a method
receiver it would be equal and will not panic. Additionally:
if p == nil { value = zero }

already provides the same goodness where desired.

Thus -1 from me.

-j

roger peppe

unread,
Sep 12, 2012, 6:40:09 AM9/12/12
to Jan Mercl, Ian Lance Taylor, beatgammit, golan...@googlegroups.com
On 12 September 2012 11:25, Jan Mercl <0xj...@gmail.com> wrote:
> On Wed, Sep 12, 2012 at 10:56 AM, roger peppe <rogp...@gmail.com> wrote:
>
> I see the benefits but I am not comfortable with the exceptional behavior.
>
> Given:
> var p *t
> var value, zero t
> // ...
>
> Then this somewhere later:
> value = *p
>
> doesn't equal:
> value = zero
>
> if p == nil and it panics instead. Now in the case of a method
> receiver it would be equal and will not panic. Additionally:
> if p == nil { value = zero }

I wouldn't propose changing the meaning of any of the
above code.

I think of my proposed change as a little like the change
that made nil maps work as if they were empty maps,
and nil channels work but always block - i.e. it doesn't
interfere and it makes some kinds of code easier to write.

It means the existing rule that allows an interface to be
created from a nil pointer with value methods becomes
more useful.

Dan Kortschak

unread,
Sep 12, 2012, 6:50:35 AM9/12/12
to roger peppe, Andrew Gerrand, beatgammit, Ian Lance Taylor, golan...@googlegroups.com
Why can't you check for nil in the String method and return the appropriate zero string value if needed?

I like that things explode when I've made a mistake, and sometimes I want to return a string that's not "" when the value is nil. Maybe I've misunderstood what you mean, but this seems like a non-problem.

Jan Mercl

unread,
Sep 12, 2012, 7:05:23 AM9/12/12
to roger peppe, Ian Lance Taylor, beatgammit, golan...@googlegroups.com
On Wed, Sep 12, 2012 at 12:40 PM, roger peppe <rogp...@gmail.com> wrote:
> I wouldn't propose changing the meaning of any of the
> above code.

That's clear to me. I tried to point out the *differences* in/compared
to the IMO analogical (non receiver) dereferencing situation. Ie.
somewhere there would be panic on nil dereferencing while elsewhere
dereferencing a nil pointer would return a zero value.

-j

roger peppe

unread,
Sep 12, 2012, 7:14:42 AM9/12/12
to Dan Kortschak, Andrew Gerrand, beatgammit, Ian Lance Taylor, golan...@googlegroups.com
On 12 September 2012 11:50, Dan Kortschak <dan.ko...@adelaide.edu.au> wrote:
> Why can't you check for nil in the String method and return the appropriate zero string value if needed?

You can't check for nil in the String method in this case, because the String
method is defined on the value type, not the pointer type.

roger peppe

unread,
Sep 12, 2012, 7:16:16 AM9/12/12
to Jan Mercl, Ian Lance Taylor, beatgammit, golan...@googlegroups.com
Yes, it would be different in those two cases.

For me, though, it seems to make sense if this rule:

: The method set of the corresponding pointer type *T is
: the set of all methods with receiver *T or T (that is, it also
: contains the method set of T).

meant that all methods on T were *actually callable* on a *T, regardless
of the value of the pointer.

Then the only code that blows up is your own code if
it directly references a nil pointer.

Rodrigo Moraes

unread,
Sep 12, 2012, 7:37:29 AM9/12/12
to golang-nuts
On Sep 12, 12:40 am, Nigel Tao wrote:
> Yet another example is an Options struct where passing a nil *Options
> means to use the default value:http://code.google.com/p/leveldb-go/source/browse/leveldb/db/options.go

And yet another one: lightweight objects that don't need any type, so
are represented by a nil pointer (this one from text/template):

type DotNode bool

func newDot() *DotNode {
return nil
}

func (d *DotNode) Type() NodeType {
return NodeDot
}

// ...

-- rodrigo

Dan Kortschak

unread,
Sep 12, 2012, 8:14:10 AM9/12/12
to roger peppe, Andrew Gerrand, beatgammit, Ian Lance Taylor, golan...@googlegroups.com
My reading/thinking caught up with my typing about a couple of minutes
after I sent the post. Sorry for the noise.

Jeff Mitchell

unread,
Sep 12, 2012, 8:23:10 AM9/12/12
to Go List


On Sep 12, 2012 6:40 AM, "roger peppe" <rogp...@gmail.com> wrote:
> I think of my proposed change as a little like the change
> that made nil maps work as if they were empty maps,
> and nil channels work but always block - i.e. it doesn't
> interfere and it makes some kinds of code easier to write.

FWIW, as a newbie, I recently spent at least an hour trying to figure out why my project developed a hanging issue before I found that I hadn't run make on two of my newer channels.

That kind of behavior only doesn't interfere if you remember to do everything properly; I would have preferred that it panic  :-)

Michael Jones

unread,
Sep 12, 2012, 9:06:15 PM9/12/12
to Nigel Tao, Andrew Gerrand, beatgammit, golan...@googlegroups.com
I think the question is really "but how would you inspect the object pointer to find and dispatch the function, as in C++ vtable." We might answer this from that angle: 

Method dispatch, as is used in some other languages with something like objectpointer->methodName() involves inspection and indirection via the indicated pointer (or implicitly taking a pointer to the object) to determine what function to invoke using the named method. Some of these languages use pointer dereferencing syntax to access the named function. In any such cases, calling a member function or method on a zero pointer understandably has no valid meaning. 

In Go, however, the function to be called by the Expression.Name() syntax is entirely determined by the type of Expression and not by the particular run-time value of that expression, including nil. In this manner, the invocation of a method on a nil pointer of a specific type has a clear and logical meaning. Those familiar with vtable[] implementations will find this odd at first, yet, when thinking of methods this way, it is even simpler and makes sense. Think of:

    func (p *Sometype) Somemethod (firstArg int) {} 

as having the literal meaning:

    func SometypeSomemethod(p *Sometype, firstArg int) {}

and in this view, the body of SometypeSomemethod() is certainly free to test it's (actual) first argument (p *Sometype) for a value of nil. Note though that the calling site invoking on a nil value must have a context of the expected type. An effort to invoke an unadorned nil.Somemethod would not work in Go because there is be no implicit "Sometype" for the typeless value nil to expand the Somemethod() call into "SometypeSomemethod()"

Warning: Stream of consciousness email from the Sydney airport. May make no sense. Quite tired.

Michael


--





--
Michael T. Jones | Chief Technology Advocate  | m...@google.com |  +1 650-335-5765

Larry Clapp

unread,
Sep 13, 2012, 10:31:19 AM9/13/12
to golan...@googlegroups.com, Nigel Tao, Andrew Gerrand, beatgammit
On Wednesday, September 12, 2012 9:06:52 PM UTC-4, Michael Jones wrote:
Warning: Stream of consciousness email from the Sydney airport. May make no sense. Quite tired.

I found it quite readable.  :) 
Reply all
Reply to author
Forward
0 new messages