-
Notifications
You must be signed in to change notification settings - Fork 90
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
Revertible thunks as function II: fix recursive overriding #940
Conversation
41639fa
to
b5818dd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just found some more typos in the comments. The logic seems good, as far as I can tell 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I can tell, this looks good, though I have to say my mental model for exactly what's going on & how it all fits together isn't great and as such I don't feel qualified to give an approving review.
I left one or two small comments but just for minor things. I don't think they need to block merging.
Revertible thunks used Rc<Closure> for the cached data. But when the revertible thunk is first created, the cached data aren't meaningful and can't be used as it is (it has free variables which need to be bound). This change better reflects this reality by using an Option, and by panicking in some illegal patterns (using the cached term before the revertible thunk is properly constructed or trying to build the cached data multiple times). Previously, we would silently accept such operations with the risk of getting spurious unbound variable errors later on.
Some multistep overriding patterns weren't handled correctly broken (see #908). Revertible thunks are to be understood as function, and the previous implementation was trying to away with actually introducing explicit function and application, by patching directly the environment of expressions with free variables. The examples presented in #908 makes it clear that this simplification doesn't work for all cases: this commit fixes the issue by introducing explicit functions and applications in the general case of merging two record fields, instead of relying on environment patching.
Co-authored-by: Viktor Kleen <viktor.kleen@tweag.io>
a9f17bd
to
bcec8a5
Compare
bcec8a5
to
1e18dfb
Compare
Revertible thunks are functions
Closes #908.
Follow-up of #924: bring the presentation of revertible thunks as just functions memoization devices to its logical conclusion by providing helper to explicitly rebuild the represented function and apply it. This explicit application was required to fix recursive overriding in the general case, see #908. Now, the implementation faithfully expresses general merging of recursive fields as
common_field = fun self => (left_field self) & (right_field self)
, when recursive record fields are understood as functions ofself
(representing the ambient record).Revertible thunks representation
This PR also reworks the representation of revertible thunks. They used to store the cached data as an
Rc<Closure>
, initialized as soon as the revertible thunks was initialized. This doesn't model revertible thunks faithfully: the cached value should be owned (as it is for normal thunks), and as long as the revertible thunks hasn't be "patched" (or, when seen as a function, applied), the cached value is meaningless and may contain free variables, id est unbound identifiers.The cached value should never be used before full initialization. This PR sets the cached value to be an
Option<Closure>
, and to panic if it used before initialization. It also ensures that initialization is done only once. The previous implementation wouldn't complain about such violation. Note that we have no choice to perform the construction of a revertible thunks in two steps, and thus observe a transitory state where the cached value is not initialized, because we are potentially building cyclic values. However, if the implementation is correct, the state where the cached value is set toNone
shouldn't really be observable.