golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
122.97k stars 17.53k forks source link

vendor: type asserting vendored code VS $GOPATH code yield awkward experience #18706

Open brenol opened 7 years ago

brenol commented 7 years ago

What version of Go are you using (go version)?

go version go1.7.4 linux/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64" GOBIN="" GOEXE="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOOS="linux" GOPATH="/home/brenol/goworkspace" GORACE="" GOROOT="/usr/local/go" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" CC="gcc" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build237439903=/tmp/go-build -gno-record-gcc-switches" CXX="g++" CGO_ENABLED="1"

What did you do?

A type assertion from a type inside another package that is actually vendored in that other package.

Given the following directory structure:

.
├── formatter
│   └── format.go
├── parser
│   ├── parser.go
│   └── vendor
│       └── github.com
│           └── brenol
│               └── formatter
│                   └── format.go
└── use_parser_and_formatter
    └── main.go

formatter/format.go:

package formatter

type Format struct{}

parser/parser.go

package parser

import "github.com/brenol/formatter"

func ReturnIt() interface{} {
    return formatter.Format{}
}

parser/vendor/github.com/brenol/formatter/format.go:

package formatter

type Format struct{}

use_parser_and_formatter/main.go:

package main

import (
    "fmt"

    "github.com/brenol/formatter"
    "github.com/brenol/parser"
)

func main() {
    v := parser.ReturnIt()
    switch val := v.(type) {
    case formatter.Format:
        fmt.Printf("I am a formatter.Format type: %T\n", val)
    default:
        fmt.Printf("I am a different type: %T\n", val)
    }
}

What did you expect to see?

I do not expect it to be of the same type - because they actually aren't - one is parser/vendor/github.com/brenol/formatter.Format and the another one is github.com/brenol/formatter/Format.

The behavior is correct, as expected. The problem is that this is cumbersome to track down and is very easy to miss. Perhaps %T should also show the package for that type, or the compiler should be more aggressive when checking for type assertions? I am not sure on how to improve the user experience on this one.

What did you see instead?

I am a different type: formatter.Format

minux commented 7 years ago

Perhaps the compiler should print package import path if any symbol (of the same type) occurs in two different packages imported.