FAQ
I've been working with net.IP a lot recently, and I've got some questions
about the design choices behind it, and generally I'd like to have a
discussion about it (because discussions are interesting, and grokking is
fun, and whatnot).

net.IP is defined as:

type IP []byte

This allows that IPv4 addresses (which are 4 bytes long) and IPv6 addresses
(which are 16 bytes long) can be represented using the same type. My guess
is that the reason for doing this is that it allows the other types in the
package which contain an IP address (such as UDPAddr and TCPAddr) and
functions which accept or return IP addresses don't have to be duplicated
to take separate IPv4 and IPv6 address types.

However, this introduces a lot of really annoying behavior. It means, first
off, that two addresses cannot be compared for equality using "==". Second,
it means that IP addresses cannot be used as may keys. Third, it means that
code cannot be written which, by type contract, expects solely IPv4 or
solely IPv6 addresses. Fourth, it means that if one or the other type is
expected, this contract is not enforced, and it requires the programmer to
either introduce an error condition or a panic condition (for example, by
calling addr.To4() or addr.To6(), which respectively convert the addr to
the given form, and return nil if addr is not the corresponding version -
using the address would then panic if it was originally the wrong type
since it'd be nil after calling addr.ToN()). Fifth, if all of these
explicit checks are not performed, it can introduce annoying bugs (for
example, the code I've been writing recently has often accidentally
propagated addresses "0.0.0.0" since I neglected to explicitly call
addr.To4(), meaning that when I accessed the first four bytes of addr, they
were 0, since addr was 16 bytes and the 4 bytes of the address were stored
from bytes 11 through 15). Sixth, it means that, since addresses are passed
by reference, they cannot be safely stored without being copied for fear
that, after returning, the caller may modify the underlying bytes (or vice
versa for the callee modifying the bytes during the call)

As I see it, a much nicer way of addressing the concern that types and
functions need to be able to accept arbitrary IP types is to have IPv4,
IPv6, and IP types, something like this:

type IP interface {
     IPVersion() int // Or "IPv4() bool" or whatever
}

type IPv4 [4]byte

func (i IPv4) IPVersion() int { return 4 }

type IPv6 [16]byte

func (i IPv6) IPVersion() int { return 6 }

This way, you could still have types like UDPAddr and TCPAddr simply have
an IP field, but you wouldn't have to worry about any of the problems I
mentioned above.

The questions I'm asking, then, are:
- Does anybody disagree with my characterization of the challenge (that is,
the need to have multiple types of IP addresses in a single type for
simplicity's sake)?
- Does anybody disagree with my characterization of the problems that the
current solution introduces?
- Does anybody think that my proposed solution fails to address the
challenge in some way, or introduces some other problems?
- Any other thoughts, feedback, or hate mail?

Cheers,
Josh

--
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+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Andrew Bursavich at Oct 10, 2014 at 12:26 am
    I've spent a little time working with net.IP and didn't run into too many
    challenges. I would suggest that your public API should support both IPv4
    and IPv6. Most of my code was agnostic to the version; where it wasn't
    I checked. When I needed to guarantee that a callee didn't alter my slice
    I returned a copy.

    Ultimately, there's no way net.IP will change in go1.


    Andy

    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Joshua Liebow-Feeser at Oct 10, 2014 at 12:41 am
    Oh, yeah I know. This less of a proposed change than a curiosity. And this
    was an IPv4-specific application.
    On Oct 9, 2014 8:26 PM, "Andrew Bursavich" wrote:

    I've spent a little time working with net.IP and didn't run into too many
    challenges. I would suggest that your public API should support both IPv4
    and IPv6. Most of my code was agnostic to the version; where it wasn't
    I checked. When I needed to guarantee that a callee didn't alter my slice
    I returned a copy.
    Ultimately, there's no way net.IP will change in go1.


    Andy

    --
    You received this message because you are subscribed to a topic in the
    Google Groups "golang-nuts" group.
    To unsubscribe from this topic, visit
    https://groups.google.com/d/topic/golang-nuts/Ian5SvVRFCY/unsubscribe.
    To unsubscribe from this group and all its topics, send an email to
    golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Mikio Hara at Oct 10, 2014 at 12:43 am

    On Fri, Oct 10, 2014 at 3:13 AM, Joshua Liebow-Feeser wrote:

    The questions I'm asking, then, are:
    - Does anybody disagree with my characterization of the challenge (that is,
    the need to have multiple types of IP addresses in a single type for
    simplicity's sake)?
    i guess that net.IP is just designed for conveying 32 or 128-bit bit
    sequence from/to the protocol stack inside the kernel, nothing less or
    more.
    - Does anybody disagree with my characterization of the problems that the
    current solution introduces?
    you can make a new type and extend it for your purpose; e.g., type
    IPv4 net.IP, func (ip IPv4) Compare(IPv4) bool. fwiw,
    http://godoc.org/github.com/mikioh/ipaddr.

    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Joshua Liebow-Feeser at Oct 10, 2014 at 3:30 am
    Yes, I could do that, but it wouldn't solve any of the issues I mentioned.
    You'd still have no guarantee from the type system that you were getting an
    IPv4 rather than IPv6 address (or vice versa), it'd still be a reference
    type, you'd still have to perform dynamic checks and conversions, etc.
    On Thu, Oct 9, 2014 at 8:43 PM, Mikio Hara wrote:

    On Fri, Oct 10, 2014 at 3:13 AM, Joshua Liebow-Feeser
    wrote:
    The questions I'm asking, then, are:
    - Does anybody disagree with my characterization of the challenge (that is,
    the need to have multiple types of IP addresses in a single type for
    simplicity's sake)?
    i guess that net.IP is just designed for conveying 32 or 128-bit bit
    sequence from/to the protocol stack inside the kernel, nothing less or
    more.
    - Does anybody disagree with my characterization of the problems that the
    current solution introduces?
    you can make a new type and extend it for your purpose; e.g., type
    IPv4 net.IP, func (ip IPv4) Compare(IPv4) bool. fwiw,
    http://godoc.org/github.com/mikioh/ipaddr.
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Mikio Hara at Oct 10, 2014 at 4:39 am

    On Fri, Oct 10, 2014 at 12:30 PM, Joshua Liebow-Feeser wrote:

    Yes, I could do that, but it wouldn't solve any of the issues I mentioned.
    i mean, making new types (in your case two array types and an
    interface type) makes sense when you're sure what's the IPv4 address.
    not sure whether you need to treat ipv6 ipv4-mapped address or
    ipv4-embedded ipv6 address for translators as IPv4 address.

    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Joshua Liebow-Feeser at Oct 10, 2014 at 4:47 am
    Except I'm pretty sure that IPv4 and IPv6 addresses are basically
    unrelated, right? They're different address spaces. I think there may be
    some scheme for embedding IPv4 addresses in an IPv6 scheme as a stopgap,
    but it's not just "use an IPv4 address as an IPv6 address." For the most
    part, it's like conflating IP addresses and MAC addresses.
    On Fri, Oct 10, 2014 at 12:39 AM, Mikio Hara wrote:

    On Fri, Oct 10, 2014 at 12:30 PM, Joshua Liebow-Feeser
    wrote:
    Yes, I could do that, but it wouldn't solve any of the issues I
    mentioned.

    i mean, making new types (in your case two array types and an
    interface type) makes sense when you're sure what's the IPv4 address.
    not sure whether you need to treat ipv6 ipv4-mapped address or
    ipv4-embedded ipv6 address for translators as IPv4 address.
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Mikio Hara at Oct 10, 2014 at 5:01 am

    On Fri, Oct 10, 2014 at 1:46 PM, Joshua Liebow-Feeser wrote:

    Except I'm pretty sure that IPv4 and IPv6 addresses are basically unrelated,
    right?
    yup, as i said above net.IP carries 32 or 128-bit bit sequences
    from/to the protocol stack.
    but it's not just "use an IPv4 address as an IPv6 address.
    you are free to blame us for the terrible leaky abstractions. ;) the
    net package currently uses ipv6 ipv4-mapped address to enable
    IPV6_V6ONLY socket option.

    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Joshua Liebow-Feeser at Oct 10, 2014 at 5:09 am
    Hahaha fair enough.
    On Fri, Oct 10, 2014 at 1:01 AM, Mikio Hara wrote:

    On Fri, Oct 10, 2014 at 1:46 PM, Joshua Liebow-Feeser
    wrote:
    Except I'm pretty sure that IPv4 and IPv6 addresses are basically
    unrelated,
    right?
    yup, as i said above net.IP carries 32 or 128-bit bit sequences
    from/to the protocol stack.
    but it's not just "use an IPv4 address as an IPv6 address.
    you are free to blame us for the terrible leaky abstractions. ;) the
    net package currently uses ipv6 ipv4-mapped address to enable
    IPV6_V6ONLY socket option.
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Nick Craig-Wood at Oct 13, 2014 at 3:10 pm

    On 09/10/14 19:13, Joshua Liebow-Feeser wrote:
    I've been working with net.IP a lot recently, and I've got some
    questions about the design choices behind it, and generally I'd like to
    have a discussion about it (because discussions are interesting, and
    grokking is fun, and whatnot).

    net.IP is defined as:

    type IP []byte

    This allows that IPv4 addresses (which are 4 bytes long) and IPv6
    addresses (which are 16 bytes long) can be represented using the same
    type. My guess is that the reason for doing this is that it allows the
    other types in the package which contain an IP address (such as UDPAddr
    and TCPAddr) and functions which accept or return IP addresses don't
    have to be duplicated to take separate IPv4 and IPv6 address types.
    I always assumed that this was to mirror the `struct sockaddr` used in
    the BSD socket interface, where the address is just a string of
    characters. Here is the original BSD definition (which incidentally is
    too short for an IPv6 address, but you get the idea). You set what type
    of address it is in sa_family and the address string in sa_data.

    struct sockaddr
    {
         unsigned short int sa_family;
         unsigned char sa_data[14];
    };

    --
    Nick Craig-Wood <nick@craig-wood.com> -- http://www.craig-wood.com/nick

    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedOct 9, '14 at 6:13p
activeOct 13, '14 at 3:10p
posts10
users4
websitegolang.org

People

Translate

site design / logo © 2021 Grokbase