-
Notifications
You must be signed in to change notification settings - Fork 18.6k
Description
Go Programming Experience
Intermediate
Other Languages Experience
No response
Related Idea
- Has this idea, or one like it, been proposed before?
- Does this affect error handling?
- Is this about generics?
- Is this change backward compatible? Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit
Has this idea, or one like it, been proposed before?
No
Does this affect error handling?
No
Is this about generics?
No
Proposal
Proposal: Allow implicit slice conversion in append operations
Abstract:
This proposal suggests allowing implicit conversion from concrete type slices to interface type slices in append operations, matching the behavior already allowed in for-range loops.
Background:
Go currently allows implicit conversion from concrete types to interface types in most expressions, including:
- Assignment operations
- Parameter passing
- Return values
- Individual element operations in for-range loops
However, Go prohibits implicit conversion of slice types in append operations, forcing developers to use for-loops as a workaround.
Motivation
The current behavior creates an inconsistency in the language. Consider this example:
// This works - implicit conversion from *struct1 to interface1
for i, s := range structs {
interface1s[i] = s
}
// This doesn't work - implicit conversion from []*struct1 to []interface1
interface1s = append(interface1s, structs...)When developers encounter this limitation, they typically fall back to this workaround:
// The workaround
for _, s := range structs {
interface1s = append(interface1s, s)
}This workaround:
- Has identical runtime characteristics to what's being disallowed
- Forces developers to write more verbose code
- Creates an inconsistency in the language design
Proposal
Allow implicit conversion of slice types in append operations when:
- The element type of the source slice can be implicitly converted to the element type of the target slice
- The conversion meets the same rules as existing implicit conversions
This would make the following code valid:
interface1s = append(interface1s, structs...)Rationale
The original reasons for prohibiting this conversion likely included concerns about:
- Performance and memory allocation costs
- Type safety
- Making conversion costs explicit
However, these concerns don't justify the inconsistency: - The loop-based workaround that developers already use has the same performance characteristics
- The type conversion is still type-safe, as it follows the rules of interface assignment
- The conversion costs are still explicit in a for-loop, just more verbosely expressed
Implementation
The compiler would be modified to:
- Check if the element type of the variadic argument in an append can be implicitly converted to the element type of the target slice
- If so, generate the code to perform the conversions, equivalent to what would be generated for a for-loop
Language Spec Changes
The language specification would need to be updated in the section describing the built-in append function. Currently, the spec states:
The append built-in function appends elements to the end of a slice. If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated. Append returns the updated slice. It is therefore necessary to store the result of append, often in the variable holding the slice itself:
slice = append(slice, elem1, elem2)
slice = append(slice, anotherSlice...)The function's first parameter slice must be a slice of type []T, and the rest are T values to append to the slice. The resulting value of append is a slice of type []T with the same underlying type as slice, and length and capacity as appropriate to accommodate the additional values.
If the capacity of slice is not large enough to fit the additional values, append allocates a new, sufficiently large underlying array that fits both the existing slice elements and the additional values. Otherwise, append re-uses the underlying array.
If the first parameter slice is nil, it is treated like a slice of length 0.
As a special case, if the second argument is a string and the slice element type is byte, append appends the bytes of the string.
The spec would be amended to add a new paragraph describing the implicit type conversion for interface types:
As a special case, if the second argument is a slice of type []S and the slice element type T is an interface type that S implements, append behaves as if each element of []S were individually appended to the slice after being implicitly converted to type T. This is equivalent to:for , x := range anotherSlice {
slice = append(slice, x)
}Where the implicit conversion from S to T occurs during the append operation of each element.
This change would make the behavior of append consistent with other operations in Go that allow implicit conversion to interface types.
Informal Change
No response
Is this change backward compatible?
Compatibility
This proposal only adds behavior and does not break existing code.
Orthogonality: How does this change interact or overlap with existing features?
No response
Would this change make Go easier or harder to learn, and why?
No response
Cost Description
No response
Changes to Go ToolChain
No response
Performance Costs
No response
Prototype
No response