{"action":"created","issue":{"url":"https://api.github.com/repos/golang/go/issues/18371","repository_url":"https://api.github.com/repos/golang/go","labels_url":"https://api.github.com/repos/golang/go/issues/18371/labels{/name}","comments_url":"https://api.github.com/repos/golang/go/issues/18371/comments","events_url":"https://api.github.com/repos/golang/go/issues/18371/events","html_url":"https://github.com/golang/go/issues/18371","id":196399536,"number":18371,"title":"proposal: add a builtin function for making an accurate copy of any value","user":{"login":"feyeleanor","id":64867,"avatar_url":"https://avatars.githubusercontent.com/u/64867?v=3","gravatar_id":"","url":"https://api.github.com/users/feyeleanor","html_url":"https://github.com/feyeleanor","followers_url":"https://api.github.com/users/feyeleanor/followers","following_url":"https://api.github.com/users/feyeleanor/following{/other_user}","gists_url":"https://api.github.com/users/feyeleanor/gists{/gist_id}","starred_url":"https://api.github.com/users/feyeleanor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/feyeleanor/subscriptions","organizations_url":"https://api.github.com/users/feyeleanor/orgs","repos_url":"https://api.github.com/users/feyeleanor/repos","events_url":"https://api.github.com/users/feyeleanor/events{/privacy}","received_events_url":"https://api.github.com/users/feyeleanor/received_events","type":"User","site_admin":false},"labels":[{"id":236419512,"url":"https://api.github.com/repos/golang/go/labels/Proposal","name":"Proposal","color":"ededed","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":7,"created_at":"2016-12-19T12:13:22Z","updated_at":"2016-12-19T21:12:26Z","closed_at":null,"body":"## Problem\r\nCurrently 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.\r\n\r\nEven 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.\r\n\r\n## Proposal\r\nThere 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.\r\n\r\n(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).\r\n\r\nA 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.\r\n\r\n## Usage\r\nA snippet of how code would look using this function:\r\n\r\n```\r\na := struct{ x, y int } { 3, 4 }\r\nb := duplicate(x)\r\nfmt.Printf(\"a.x: %v, a.y: %v\\n\", a.x, a.y)\r\nfmt.Printf(\"b.x: %v, b.y: %v\\n\", b.x, b.y)\r\n```\r\n\r\nin both cases fmt.Printf() will print out the same values for the x and y fields.\r\n\r\n## Problems\r\nIn 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.\r\n\r\n- The former is inexpensive but possibly _too_ shallow;\r\n- the latter may not make sense for all reference types;\r\n- perhaps reference types shouldn't duplicate at all;\r\n- perhaps _**duplicate()**_ is dangerous enough to be part of *unsafe*."},"comment":{"url":"https://api.github.com/repos/golang/go/issues/comments/268079833","html_url":"https://github.com/golang/go/issues/18371#issuecomment-268079833","issue_url":"https://api.github.com/repos/golang/go/issues/18371","id":268079833,"user":{"login":"bradfitz","id":2621,"avatar_url":"https://avatars.githubusercontent.com/u/2621?v=3","gravatar_id":"","url":"https://api.github.com/users/bradfitz","html_url":"https://github.com/bradfitz","followers_url":"https://api.github.com/users/bradfitz/followers","following_url":"https://api.github.com/users/bradfitz/following{/other_user}","gists_url":"https://api.github.com/users/bradfitz/gists{/gist_id}","starred_url":"https://api.github.com/users/bradfitz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bradfitz/subscriptions","organizations_url":"https://api.github.com/users/bradfitz/orgs","repos_url":"https://api.github.com/users/bradfitz/repos","events_url":"https://api.github.com/users/bradfitz/events{/privacy}","received_events_url":"https://api.github.com/users/bradfitz/received_events","type":"User","site_admin":false},"created_at":"2016-12-19T21:12:26Z","updated_at":"2016-12-19T21:12:26Z","body":"And even if you need to use reflect, it's just:\r\n\r\n```go\r\nfunc duplicate(v interface{}) interface{} {\r\n\trv := reflect.New(reflect.TypeOf(v)).Elem()\r\n\trv.Set(reflect.ValueOf(v))\r\n\treturn rv.Interface()\r\n}\r\n```\r\n"}}
{"actor":{"display_login":"bradfitz"}}