Fix record.update
by making record.insert
act consistently
#1669
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The issue
Although this has been hidden by polymorphic contracts,
record.insert
has been subtly broken. Most function - if not all - of the stdlib, by design, ignore empty optional fields. This is in particular the case ofrecord.remove
andrecord.has_field
. However,record.insert
doesn't follow the same convention, for some reason, and fail to insert a value if there's already a field, even if the latter is an empty optional field.Thus, when defining e.g.
record.update
, we end up with the following surprising result:Indeed,
has_field
doesn't see the empty optional field, but%record_insert%
does. This is currently mitigated forstd.record.insert
because polymorphic contracts generates "spurious" values (contract application that, if ever evaluated, would raise a missing field definition), and thus are properly considered byhas_field
and removed. However, for an upcoming change (contract elision for static type annotation), the polymorphic contract is elided and the behavior above will be triggered from the normalrecord.update
.Content
I started by making variants of
has_field
andrecord_remove
that are able to see through empty optional fields. Only then I a realized that the actual issue wasn't thathas_field
was ignoring empty optionals, but rather thanrecord_insert
was the only primop to not do so. Still, I think those variants will prove useful, as I believe we will have demand for the corresponding functions in the stdlib - that is, functions that are able to see and manipulate empty optionals. I propose to let the code stay, even if it's not strictly required for the issue addressed by this PR.The heart of the fix is then just to make
record_insert
to beBackward compatiblity
This makes
record.insert
succeeds on more programs, as it would refuse to insert something if there was an empty optional already before this change. Now it has the same behavior on previous cases, but it doesn't fail when there is a non-empty optional field already.