Wondering about conversion of slices

95 views
Skip to first unread message

Matt Cudmore

unread,
Mar 3, 2012, 9:10:33 AM3/3/12
to golan...@googlegroups.com
I can't recall whether I've encountered this case before, and suspect that there is a simple answer to my question, but I wonder why a slice cannot be converted (implicitly or explicitly) as in this example:


Is there a general explanation and justification for this? I would like to fully understand and agree with the error "cannot use more (type []B) as type []A in function argument". If some point in the specification section "Properties of types and values" is relevant, I haven't quite made sense of it; but it does say that "T0 and T1 are different because they are named types with distinct declarations" (which I don't think is an satisfying explanation).

Thank you!

p.s. Hello golang-nuts; I am greatly enjoying using this language you're all creating. -Matt

Kyle Lemons

unread,
Mar 3, 2012, 2:33:48 PM3/3/12
to Matt Cudmore, golan...@googlegroups.com
Part of the purpose of naming types is that it prevents you from passing "comatible" types accidentally.  It would not do, for instance, to pass a time.Duration as a `type Time int64`.  This is secondary to the discussion of slices, however, because a []T is an unnamed type, and therefore only assignable to identical unnamed types or a named version of that type (type TList []T).  The reason for this is that there is no guarantee that the memory layout of two differently-typed slices is the same, so allowing you to pass "comatible" element type slices could incur implicit duplication of the slice, breaking its slice semantics.  This is particularly the case when A is an interface and B is a concrete type; interfaces are almost certainly not the same size or memory layout as the concrete slice.

chris dollin

unread,
Mar 3, 2012, 3:09:15 PM3/3/12
to Matt Cudmore, golan...@googlegroups.com
On 3 March 2012 14:10, Matt Cudmore <cudmo...@gmail.com> wrote:
> I can't recall whether I've encountered this case before, and suspect that
> there is a simple answer to my question, but I wonder why a slice cannot be
> converted (implicitly or explicitly) as in this example:
>
> http://play.golang.org/p/MU-1-1j0gH

Even if a B and a C "can be treated as" A's (in your example, because
both B and C are interfaces embedding A), []B and []C are not []As;
this is (I think) a general result, ie, not restricted to Go.

And here's why: you can put any A into a []A, but you can't put any
A into a []B, because the elements of B MUST be Bs.

Allowing a []B to be treated as an []A would mean allowing smuggling
a non-B into a []B by treating that []B as an []A and then putting a C
(which is an A but not a B) into it.

That would either break static type checking (Go's choice: a []B is not
a []A) or require run-time type checks when assigning into an array
element (Java's choice, but the sort of implicit performance hit that
is very unGo.)

Chris

--
Chris "allusive" Dollin

Matt Cudmore

unread,
Mar 4, 2012, 2:01:13 AM3/4/12
to golan...@googlegroups.com, Matt Cudmore
On Saturday, March 3, 2012 12:09:15 PM UTC-8, ehedgehog wrote:

Allowing a []B to be treated as an []A would mean allowing smuggling
a non-B into a []B by treating that []B as an []A and then putting a C
(which is an A but not a B) into it.

This is very clear and general (not specific to Go); and so I suppose that Go's choice (e.g. a []B is not a []A) is why the copy (line 72 in my example) doesn't work, even though the intent (lines 64-68) is acceptable. Thanks.

Steven Blenkinsop

unread,
Mar 4, 2012, 4:19:14 AM3/4/12
to golang-nuts
a) The point of copy is that it handles all kinds of boundary cases, such as overlapping arguments. Since the slices are of different types, this cannot happen, so it is not necessary.

b) Copy uses a memmove internally for efficiency, which just blindly moves the data into the new memory. This would be broken by the fact that you [may] need to compute the B value corresponding to each A value.

Point (b) could be overcome by defining a second, less efficient, version of copy that handles this case, however this would hide the inefficiency, which is something that tends to be avoided in Go wherever possible. Plus, (a) says it isn't actually needed, so it's better to just write the loop to do the copy.
Reply all
Reply to author
Forward
0 new messages