-
Notifications
You must be signed in to change notification settings - Fork 18k
proposal: add a builtin function for making an accurate copy of any value #18371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
There is already a way to do shadow copy of a value, just
use assignment:
a := struct{ x, y int } { 3, 4 }
b := a
fmt.Printf("a.x: %v, a.y: %v\n", a.x, a.y)
fmt.Printf("b.x: %v, b.y: %v\n", b.x, b.y)
What value does the proposed "duplicate" function add?
|
So, put it in a library, rather than asking each user to do it by hand? Actually, it exists already: https://godoc.org/?q=deepcopy Why does it need to be part of the language? And if it were part of the language, I'm sure it would surprise people to learn that a function named duplicate only makes a shallow and not a deep clone of its argument. |
Perhaps a reflect.DeepCopy (to mirror reflect.DeepEqual) is better?
However, there is already a reflect.Copy, and it does something
unrelated (it relates the copy builtin function.)
But still, I think needing to do deep copy on a value suggests
an API design problem.
|
As others have already pointed out, making an shallow copy of a type in Go is already straightforward. Implementing a general deep copy is problematic. What should
If we were to copy this correctly, then all the slice and pointer references would The only time I've actually needed a general deep copy, json.Marshal
It would be useful to have some specific cases where you see a more
I tend to agree with this. |
This is not a proposal for a DeepCopy mechanism. This is a method for making an exact duplicate of a value, including its unexported fields. |
Make a shadow copy is as simple as a regular assignment, why do we need a
new built-in function?
What am I missing here?
|
And even if you need to use reflect, it's just: func duplicate(v interface{}) interface{} {
rv := reflect.New(reflect.TypeOf(v)).Elem()
rv.Set(reflect.ValueOf(v))
return rv.Interface()
} |
Not if it has unexported fields. |
@feyeleanor minux's first reply shows that assignment does indeed copy the unexported struct fields. |
And even if you have to use reflect, you can still copy unexported fields:
(based on @bradfitz's code above):
https://play.golang.org/p/YcJEcfUMXK
|
I'm going to close this, since it's unclear what benefit there is having this more built-in than it already is. Feel free to reopen if you have a more formal proposal. |
In which case I've misunderstood the documentation for reflect.Value.Set() and reflect.Value.CanSet(). If @bradfitz's code is robust in all circumstances (in addition to @minux's example I've tried it with an unexported struct type containing unexported fields from one of my own packages & that works) then it would still make sense to either have a convenience method on reflect.Value:
or to include an example in the documentation for reflect. |
https://blog.golang.org/laws-of-reflection is worth reading. |
Unfortunately Laws of Reflection doesn't cover this and the Third Law coverage which is relevant is obscured by using an example where addressability is the basis for settability. An example in the reflect documentation would leave no room for misunderstanding. |
@feyeleanor Assuming you actually mean this:
but even if this trivial function was provided, what does this The documentation of Value.Set and Value.CanSet seems right BTW the description of this issue says "add a builtin function for making an accurate copy of any value". None of the reflect package functions are built in. The builtin "function" for making an accurate copy of any value is the assignment operator. |
Problem
Currently there seems to be no general method for making a shallow but complete copy of an existing value of arbitrary type in a Go program. This is particularly true when a value is a struct with unexported fields.
Even using reflection to perform a direct binary copy is a minefield of segfaults, unaddressable values and faked []byte using reflection which makes such code difficult to reason about.
Proposal
There are cases where making a full and accurate copy of an existing value - even a struct value with unexported fields - is a perfectly reasonable thing to do so I propose two possible additions to Go which would support this without compromising the key premise of unexported fields: that they cannot be modified except by functions and methods in the package where they're defined.
(Making an exact copy is not conceptually the same as changing the field contents, the problem is an artefact of Go's reflection system being implemented as a package rather than with some other API).
A new builtin function with signature duplicate(v Type) Type would return a complete and faithful shallow copy of any value. At the byte level it would be binary identical to the value it's created from and all the usual rules would apply to it, so unexported fields would still only be changeable by functions defined in its source package.
Usage
A snippet of how code would look using this function:
in both cases fmt.Printf() will print out the same values for the x and y fields.
Problems
In the case of reference types such as maps, slices, interfaces, pointers, channels, etc. a decision would have to be made as to whether to make a copy of the reference (slice header, etc.) or a copy of the underlying values.
The text was updated successfully, but these errors were encountered: