Using interface types as map keys

(I started a conversation on Twitter but @adg suggested it would be a good time to try out this forum.)

@adg has advised in the past that it isn’t a good idea to use interface types as map keys because if an implementation is provided which has an incomparable type (map, slice, func), it will result in a runtime panic.

https://talks.golang.org/2015/tricks.slide#25 (and also Docker pull request 15751; can’t post the link because this forum has an annoying link limit for new users)

This is of course sensible and I agree in general, but I’ve also found cases where I’m not easily able to avoid using an interface in a map key. The one that comes to mind at the moment is when making use of http.ConnState callback. Sometimes I’ve used that to get statistics on the number of connections in various states, and in that case I’ve used c.RemoteAddr() as my map key. But at other times, it’s more natural to use net.Conn itself as the key. See, for example, @bradfitz’s recent CL for net/http/httptest:

https://golang.org/cl/15151

where he uses map[net.Conn]bool to represent a set of net.Conns.

One way to work around this would be to use a map[string]net.Conn instead of a map[net.Conn]bool and then use c.RemoteAddr() as the key.

Is this kind of defensive programming warranted, though?

In my point of view, there is always a chance you have runtime panic even if you’re writing code that you feel most comfortable with. Also, things can be worked around to reduce the probabilities of runtime panic such as do a type check before using it to access value in the map.

So… do most comfortable way for yourself.

In my point of view, there is always a chance you have runtime panic even if you’re writing code that you feel most comfortable with.

In most of the code I write, I strive to make it so that runtime panics only occur if I (the programmer) have made a mistake.

Also, things can be worked around to reduce the probabilities of runtime panic such as do a type check before using it to access value in the map.

In this case, the concrete type that it’s going to be 99.9% of the time is the unexported type net.conn, so that doesn’t apply.

If I’m going to work around it, I think it’s simpler to avoid using the interface type as the map key in the first place.

If you use third-party libraries, there will be mistakes.

In this case, the concrete type that it’s going to be 99.9% of the time is the unexported type net.conn, so that doesn’t apply.

Then the case condition go to you don’t want to work around.

And what do you mean by unexported type net.conn exactly? Didn’t net.Conn is exported?

I considered that problem when I wrote that code but I realized in this case, all net.Conn cases are from net.Listener (newLocalListener in that file), so it’s safe.

1 Like

The problem is: you have a net.Conn that you want to use as a map key. If it’s a *net.conn, then that’s safe; if it’s some other concrete type, then it might not be.

  1. How do you check whether the net.Conn is a *net.conn?
  2. What do you do if it isn’t?

I’m claiming that if you care about protecting yourself from this problem, the solution is to not use a net.Conn as a map key at all.

My question is: should I care?

Package reflect can tell you if it’s a pointer or not.

What do you do if it isn’t?

If it’s not exported, how can you access it to use as key type of map?

Package reflect can tell you if it’s a pointer or not.

This is very much more work/trouble than not using a net.Conn as a map key.

If it’s not exported, how can you access it to use as key type of map?

The question is about using net.Conn as a map key.

This is really a matter of context. Who will be using the map? How will the map be accessible? What might you be using as a key (concrete types)? Where are those types coming from (are you writing them, 3rd party lib)? Who else will be working with this code (will they recognize the same concerns when making changes)?

If the surface area is really small, I wouldn’t fret over it. Otherwise, why risk it.

This is very much more work/trouble than not using a net.Conn as a map key.

If you get too many trouble with it, I don’t see any point that why you’re arguing/wondering using it or not.

The question is about using net.Conn as a map key.

I’m completely confused by what have you said in the post… :sweat:

I’m completely confused by what have you said in the post…

Likewise :stuck_out_tongue:

Thanks Brad! I don’t quite understand/agree, but we can keep that discussion on the CL.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.