Skip to content
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

struct-copy doesn't recognize contracted super struct info #3270

Open
sorawee opened this issue Jun 28, 2020 · 9 comments
Open

struct-copy doesn't recognize contracted super struct info #3270

sorawee opened this issue Jun 28, 2020 · 9 comments
Labels
bug Something isn't working correctly

Comments

@sorawee
Copy link
Collaborator

sorawee commented Jun 28, 2020

#lang racket

(module first racket
  (provide (contract-out (struct foo ([x any/c])))
           (contract-out (struct (bar foo) ([x any/c]))))
  (struct foo (x))
  (struct bar foo ()))

(require 'first)

(struct-copy bar (bar 1) [x #:parent foo 2])

fails with:

struct-copy: identifier not bound to a parent struct
  at: foo
  in: (struct-copy bar (bar 1) (x #:parent foo 2))

Note that this has been failing, even before #2700.

@sorawee
Copy link
Collaborator Author

sorawee commented Jul 2, 2020

The problem is that https://github.com/racket/racket/blob/master/racket/collects/racket/private/define-struct.rkt#L1002 uses free-identifier=? to test if the specified parent id is the same as one of identifiers in the struct info or not. Because contract-out generates a new identifier, they won't be free-identifier=? to each other.

One possible fix is to add yet another struct prop, say, struct-identity-info to keep the original identifier around. contract-out will attach this property, which contains the original identifier. This would allow struct-copy to use the content of struct-identity-info if it's available. Note that struct infos generated by define-struct won't need this property.

Does this look like a good idea?

CC: @mflatt, @rmculpepper

@rfindler
Copy link
Member

rfindler commented Jul 2, 2020 via email

@sorawee
Copy link
Collaborator Author

sorawee commented Jul 2, 2020

Not really. In fact, a better example is:

#lang racket

(module first racket
  (provide (contract-out (struct foo ([x any/c])))
           (struct-out bar))
  (struct foo (x))
  (struct bar foo ()))

(require 'first)

(struct-copy bar (bar 1) [x #:parent foo 2])

In the above program bar is not contract-out-ed at all. So there's really nothing that we can do with the struct info of bar.

@rfindler
Copy link
Member

rfindler commented Jul 2, 2020

Maybe in that example, bar isn't really a substruct of foo (outside of the module)?

@rfindler
Copy link
Member

rfindler commented Jul 2, 2020

@chrdimo what do you think about these examples?

@samth
Copy link
Sponsor Member

samth commented Jul 2, 2020

Saying that bar isn't a substruct of foo is effectively saying that we can't use struct-copy on bar at all, right? Note that this does work, suggesting that contract-out thinks that bar is a substruct of foo:

#lang racket
(module first racket
  (provide (contract-out (struct foo ([x any/c])))
           (struct-out bar))
  (struct foo (x))
  (struct bar foo ()))

(module second racket
  (require (submod ".." first))
  (provide (contract-out (struct (bar foo) ([x any/c])))))
(require 'second)
(bar 1)

@sorawee
Copy link
Collaborator Author

sorawee commented Jul 2, 2020

@samth the super struct position was recently deprecated (by me), precisely because I don't have a good way to check that foo is a super struct of bar after it's contracted.

@sorawee
Copy link
Collaborator Author

sorawee commented Jul 2, 2020

Maybe in that example, bar isn't really a substruct of foo (outside of the module)?

Doesn't that imply that the following code should fail?

#lang racket

(module first racket
  (provide (contract-out (struct foo ([x any/c])))
           (struct-out bar))
  (struct foo (x))
  (struct bar foo ()))

(require 'first)

(foo-x (bar 1)) ; 1

But clearly, you have put a lot of effort into making it work (impersonator, chaperone, etc.).

@rfindler
Copy link
Member

rfindler commented Jul 2, 2020

That's a good point.

I do think that (struct-out bar) should behave the same as (contract-out (struct bar ....)) where the ellipsis contains the right number of any/cs just in the same way that (provide x) should be the same as (provide (contract-out [x any/c])). Unfortunately, the latter is not always the same for some technical reasons and so we might not get the former either. Perhaps this is one of those situations where we wish we coudl fix it, but we won't end up fixing it.

Which brings us back to the earlier example, where both bar and foo are in contract-out but not quite cooperating enough(?).

@jackfirth jackfirth added the bug Something isn't working correctly label Jul 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working correctly
Projects
None yet
Development

No branches or pull requests

4 participants