{"action":"created","issue":{"url":"https://api.github.com/repos/gopherjs/gopherjs/issues/633","repository_url":"https://api.github.com/repos/gopherjs/gopherjs","labels_url":"https://api.github.com/repos/gopherjs/gopherjs/issues/633/labels{/name}","comments_url":"https://api.github.com/repos/gopherjs/gopherjs/issues/633/comments","events_url":"https://api.github.com/repos/gopherjs/gopherjs/issues/633/events","html_url":"https://github.com/gopherjs/gopherjs/issues/633","id":223935716,"number":633,"title":"Proposal: explicit *js.Object-special struct types","user":{"login":"myitcv","id":3374574,"avatar_url":"https://avatars2.githubusercontent.com/u/3374574?v=3","gravatar_id":"","url":"https://api.github.com/users/myitcv","html_url":"https://github.com/myitcv","followers_url":"https://api.github.com/users/myitcv/followers","following_url":"https://api.github.com/users/myitcv/following{/other_user}","gists_url":"https://api.github.com/users/myitcv/gists{/gist_id}","starred_url":"https://api.github.com/users/myitcv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/myitcv/subscriptions","organizations_url":"https://api.github.com/users/myitcv/orgs","repos_url":"https://api.github.com/users/myitcv/repos","events_url":"https://api.github.com/users/myitcv/events{/privacy}","received_events_url":"https://api.github.com/users/myitcv/received_events","type":"User","site_admin":false},"labels":[{"id":254984863,"url":"https://api.github.com/repos/gopherjs/gopherjs/labels/Proposal","name":"Proposal","color":"e6e6e6","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":7,"created_at":"2017-04-24T20:07:10Z","updated_at":"2017-04-25T19:18:17Z","closed_at":null,"body":"Following discussion with @neelance and @shurcooL \r\n\r\nCurrently (as of https://github.com/gopherjs/gopherjs/commit/265040a1352e0bb611e87f5b985bf83600c66cce to be explicit) `*js.Object`-special struct types are _inferred_ from struct types which have a `*js.Object`-typed field as the first field and a least one field with a `js` tag (as described in the [wiki](https://github.com/gopherjs/gopherjs/wiki/JavaScript-Tips-and-Gotchas)):\r\n\r\n```go\r\ntype T struct {\r\n\to *js.Object\r\n\r\n\tName     string `js:\"name\"`\r\n\tAge      int    \r\n\tlocation string\r\n}\r\n```\r\n\r\nWe propose changing this to a more explicit approach where the `*js.Object`-typed field is tagged with `jsspecial:\"true\"`, and the `js` field tags are optional:\r\n\r\n```go\r\ntype T struct {\r\n\to *js.Object `jsspecial:\"true\"`  // let's bikeshed the tag name...\r\n\r\n\tName     string `js:\"name\"`\r\n\tAge      int    \r\n\tlocation string\r\n}\r\n```\r\n\r\nUnder this proposal it would be an error for a struct to declare more than one field annotated with `jsspecial:\"true\"` (after embedding).\r\n\r\nThe impact of this change would be:\r\n\r\n* to make `*js.Object`-special struct types more explicit and therefore easier to explain/understand.  We could even make it a compiler error to use a non-pointer value of such types (a point which is currently only enforced via [guidance in the wiki](https://github.com/gopherjs/gopherjs/wiki/JavaScript-Tips-and-Gotchas))\r\n* to do away with the \"inner\" and \"outer\" parts (using the [wiki parlance](https://github.com/gopherjs/gopherjs/wiki/JavaScript-Tips-and-Gotchas)), leaving just the \"inner\" part (which we can then refer to as effectively a `*js.Object` value). This helps remove any sort of confusion around there being two parts: every assignment to a field is redirected onto the `*js.Object` value in the `jsspecial` tagged field\r\n* by making the `js` tag optional for fields we follow a pattern much closer to, for example, `encoding/json` tags, i.e. a familiar pattern (with the exception that even unexported fields are supported). The `js` tag would then only be required where a different name is required on the underlying `*js.Object`\r\n\r\nHere's a quick example under this proposal:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"github.com/gopherjs/gopherjs/js\"\r\n)\r\n\r\ntype T struct {\r\n\to *js.Object `jsspecial:\"true\"`\r\n\r\n\tName     string `js:\"name\"`\r\n\tAge      int    \r\n\tlocation string\r\n}\r\n\r\nfunc main() {\r\n\to := &T{o: js.Global.Get(\"Object\").New()}\r\n\r\n\to.Name = \"Lorem\"\r\n\to.Age = 100\r\n\to.location = \"Ipsum\"\r\n\r\n\tjs.Global.Get(\"console\").Call(\"log\", o)\r\n\r\n\t// outputs\r\n\t//\r\n\t// { name: 'Lorem', Age: 100, location: 'Ipsum' }\r\n}\r\n```\r\n\r\n_to be clear, under the current implementation this outputs simply `{ name: 'Lorem' }`_\r\n\r\nThe following would however be a compile error for struct type `S`:\r\n\r\n```go\r\ntype T struct {\r\n\to *js.Object `jsspecial:\"true\"`\r\n\r\n\tName     string `js:\"name\"`\r\n\tAge      int    \r\n\tlocation string\r\n}\r\n\r\ntype S struct {\r\n\t*T\r\n\r\n\tp *js.Object `jsspecial:\"true\"`  // ERROR multiple fields tagged `jsspecial:\"true\"` in S\r\n}\r\n```\r\n\r\nThis would be a \"breaking\" change:\r\n\r\n1. developers will need to annotate their `*js.Object` fields with the new tag\r\n2. anyone relying on the two parts of such objects will lose the \"outer\" part\r\n\r\nThe first of these points is easily fixed; making the change also allows the new code to be backwards compatible with previous versions of GopherJS.\r\n\r\nIt's assumed that very, very few people (indeed anyone?) are relying on the \"outer\" part in the current implementation; please shout if that's a bad assumption\r\n\r\nRelated:\r\n\r\n* #236\r\n* #401\r\n\r\n# Open questions\r\n\r\n~#### Q1: Do we make methods defined on `*js.Object`-special struct types an error?~\r\n\r\n~[Context](https://github.com/gopherjs/gopherjs/issues/633#issuecomment-297122798)~\r\n\r\n~Probably, yes.~\r\n\r\n#### Q2: What should the identifying tag for such struct types be?\r\n\r\n1. ~`jsspecial:\"true\"` - ruling this out because it was intentionally provocatively bad~\r\n2. `mapjsfields:\"true\"` @neelance \r\n3. `js:\"*\"` @flimzy "},"comment":{"url":"https://api.github.com/repos/gopherjs/gopherjs/issues/comments/297136518","html_url":"https://github.com/gopherjs/gopherjs/issues/633#issuecomment-297136518","issue_url":"https://api.github.com/repos/gopherjs/gopherjs/issues/633","id":297136518,"user":{"login":"flimzy","id":8555063,"avatar_url":"https://avatars3.githubusercontent.com/u/8555063?v=3","gravatar_id":"","url":"https://api.github.com/users/flimzy","html_url":"https://github.com/flimzy","followers_url":"https://api.github.com/users/flimzy/followers","following_url":"https://api.github.com/users/flimzy/following{/other_user}","gists_url":"https://api.github.com/users/flimzy/gists{/gist_id}","starred_url":"https://api.github.com/users/flimzy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flimzy/subscriptions","organizations_url":"https://api.github.com/users/flimzy/orgs","repos_url":"https://api.github.com/users/flimzy/repos","events_url":"https://api.github.com/users/flimzy/events{/privacy}","received_events_url":"https://api.github.com/users/flimzy/received_events","type":"User","site_admin":false},"created_at":"2017-04-25T19:18:17Z","updated_at":"2017-04-25T19:18:17Z","body":"> Not sure I follow (the bit about a \"cleaner spec\")?\r\n\r\nJust saying that not requiring an extra tag would be a bit cleaner.   But that's irrelevant, since it's not a good option :)"}}
{"actor":{"display_login":"flimzy"}}