1. 19
  1.  

  2. 7

    This is just bad semantics. You’d expect that coercing a type to its supertype preserves all properties shared with the supertype including nil. For “implementation reasons” this isn’t happening.

    1. 2

      Not so. Printing all the details…

      fmt.Printf(”%#v %#v %#v %v”, t, t2, thing, thing.P == nil)

      Provides…

      &main.T{}

      (*main.T)(nil)

      &main.Thing{P:(*main.T)(nil)}

      false

      Clearly the interface P in the third position is not nil. Rather it is implemented by a nil *T

      It’s fair to dislike the Go interface mechanism, but it is not the case that this is type / supertype.

      1. 1

        Hm, maybe I’m misunderstanding then, but if isNil is a property of all types in Go and I can silently convert a value to a substantiation of an interface then I’d expect isNil to be preserved. That silent coercion is the subtyping relationship.

        Now also clearly this doesn’t quite work from a memory perspective since coercing to an interface means we need to reference the methods somehow or another, but that’s why I think this is a convenient-but-wrong kind of behavior.

        1. 1

          Think of Go interfaces as a pair of a type tag and a value of that type. In the original code the call…

          factory(t2)

          Go implicitly creates a P interface instance as the pair (*T, nil)

          And the original predicate asks…

          Given a pair (*T, nil) and the constant nil are they == ?

          And the answer is false.

          In another comment on this page I modified the example to…

          var pnil P = (*T)(nil); fmt.Println(thing.P == pnil)

          In this case Go implicitly creates a P interface instance as the pair (*T, nil) and the variable pnil is assigned that value.

          In this example the predicate asks…

          Given a pair (*T, nil) and another pair (*T, nil) are they == ?

          In this case the answer is true.

    2. 3

      The following prints true.

      var pnil P = (*T)(nil); fmt.Println(thing.P == pnil)

      However the real problem is this smells bad – avoid having to inspect interface implementations.

      The simple solution is having lint warn of comparing an interface via ==

      1. [Comment removed by author]

        1. 1

          Agreed, I think the false positives would outweigh the offenses. This only adds to my inclination that typed nil isn’t a great problem for Go 2.