{"action":"created","issue":{"url":"https://api.github.com/repos/plt/racket/issues/879","labels_url":"https://api.github.com/repos/plt/racket/issues/879/labels{/name}","comments_url":"https://api.github.com/repos/plt/racket/issues/879/comments","events_url":"https://api.github.com/repos/plt/racket/issues/879/events","html_url":"https://github.com/plt/racket/pull/879","id":57431921,"number":879,"title":"Add a contract combinator for prefab structs","user":{"login":"takikawa","id":64192,"avatar_url":"https://avatars.githubusercontent.com/u/64192?v=3","gravatar_id":"","url":"https://api.github.com/users/takikawa","html_url":"https://github.com/takikawa","followers_url":"https://api.github.com/users/takikawa/followers","following_url":"https://api.github.com/users/takikawa/following{/other_user}","gists_url":"https://api.github.com/users/takikawa/gists{/gist_id}","starred_url":"https://api.github.com/users/takikawa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/takikawa/subscriptions","organizations_url":"https://api.github.com/users/takikawa/orgs","repos_url":"https://api.github.com/users/takikawa/repos","events_url":"https://api.github.com/users/takikawa/events{/privacy}","received_events_url":"https://api.github.com/users/takikawa/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-02-12T08:43:29Z","updated_at":"2015-03-11T17:29:18Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/plt/racket/pulls/879","html_url":"https://github.com/plt/racket/pull/879","diff_url":"https://github.com/plt/racket/pull/879.diff","patch_url":"https://github.com/plt/racket/pull/879.patch"},"body":"The `prefab/c` in this PR matches up with the proposed `Prefab` type in TR and specifies a prefab key and a contract for each of the fields."},"comment":{"url":"https://api.github.com/repos/plt/racket/issues/comments/78312672","html_url":"https://github.com/plt/racket/pull/879#issuecomment-78312672","issue_url":"https://api.github.com/repos/plt/racket/issues/879","id":78312672,"user":{"login":"takikawa","id":64192,"avatar_url":"https://avatars.githubusercontent.com/u/64192?v=3","gravatar_id":"","url":"https://api.github.com/users/takikawa","html_url":"https://github.com/takikawa","followers_url":"https://api.github.com/users/takikawa/followers","following_url":"https://api.github.com/users/takikawa/following{/other_user}","gists_url":"https://api.github.com/users/takikawa/gists{/gist_id}","starred_url":"https://api.github.com/users/takikawa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/takikawa/subscriptions","organizations_url":"https://api.github.com/users/takikawa/orgs","repos_url":"https://api.github.com/users/takikawa/repos","events_url":"https://api.github.com/users/takikawa/events{/privacy}","received_events_url":"https://api.github.com/users/takikawa/received_events","type":"User","site_admin":false},"created_at":"2015-03-11T17:29:18Z","updated_at":"2015-03-11T17:29:18Z","body":"While trying to integrate this into TR, I hit a design issue that hadn't come up before.\r\n\r\nHere's an example (that doesn't actually run right now) to illustrate the issue:\r\n\r\n````\r\n#lang racket\r\n\r\n(module t typed/racket\r\n  (struct parent ([x : String]) #:prefab)\r\n  (struct child parent ([y : Integer]) #:mutable #:prefab)\r\n  (: a-child Parent) ; subtyping\r\n  (define a-parent (child \"foo\" 0))\r\n  ;; exported with a contract for `parent` struct\r\n  (provide a-parent))\r\n\r\n(require (submod \".\" t))\r\n\r\n;; the contract doesn't prevent this\r\n(struct parent (x) #:prefab)\r\n(struct child parent (y) #:mutable #:prefab)\r\n(set-child-y! a-parent \"not an integer\")\r\n````\r\n\r\nThis example illustrates how a `prefab/c` isn't sufficient protection when exporting a prefab with a supertype of its actual type, because that doesn't protect the subtype fields.\r\n\r\nOne solution might be to add `#:substruct-accessor` and `#:substruct-mutator` options to `prefab/c` that allow a contract to be specified for the extra accessors/mutators that might exist (with the default being to do nothing). This is a little weird in the case that a non-prefab struct extends a prefab struct (surprisingly this is allowed in Racket), but in that case it can still find all the prefab parts of the struct hierarchy via `struct-info`.\r\n\r\nAnother would be to define a custom contract just for TR that basically does what I described above but only for TR. It could re-use `prefab/c`'s projection but also apply another layer of chaperoning.\r\n\r\nDo either of these approaches make sense?"}}