I’ve been playing around with my toy project, which involves building a collection of interfaces and quickly ran into the problem that a pretty normal-seeming use-case doesn’t work:
func NewCollection(list []Interface) { ... }
// later in another function
list := []ImplementsInterface{...}
c := NewCollection(list)
In other words, a slice of ImplementsInterface, being an unnamed composite type, isn’t the same type as a slice of Interface, a different unnamed composite type.
Fine, it made sense, so I naively set about manually allocating a new slice of Interface in the calling code, which worked but got ugly fast, like this:
list := []ImplementsInterface{ ... }
newlist := make([]Interface, len(list))
for i, l := range list {
newlist[i] = Interface(l)
}
NewCollection(newlist)
Finally, after returning to code riddled with this type of stuff after a while, muttering curses and decided that there had to be a better way, I found out that changing the original argument to call not a slice, but a variadic argument, everything works the way it should:
func NewCollection(list ...Interface) { ... }
// later in another function
list := []ImplementsInterface{...}
c := NewCollection(list)
This is fantastic realization and changing function parameters to match this style should reduce boilerplate elsewhere, but I’m curious about a few things. From the language spec:
If f is variadic with a final parameter p of type …T, then within f the type of p is equivalent to type T.
Apparently …T is equivalent to T except that it allows for passing in implementers of T as detailed above, so my two big questions are:
- Is there any trap, side effect, or reason not to use variadics in this fashion?
- If …T is equivalent to T, why can …T handle interface implementations appropriately, but T cannot? I don’t excessively mind using …T in these case assuming the answer to (1) is “No.”, but I don’t understand the logic for the compiler not “figuring things out” in the case of T just as simply as …T.
Finally, I this topic got away from me on length, but here’s a playground link with this behavior shown.