Replies: 2 comments 1 reply
-
For the record, merlin used to do this; but we've moved away from that many years ago. |
Beta Was this translation helpful? Give feedback.
0 replies
-
For me the behavior reported with first-class module is a bug that should be fixed: Two questions:
|
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
(Note: this issue is meant as a discussion, not a bug report. I plan to close it just after submitting it. I've thought about using other means of communication, but Github looks like the place most likely to be looked at by people interested in the discussion.)
We had a few discussions with colleagues about whether the compiler should support runtime values that are bigger than their type suggests. Currently it can only be done with
Obj.magic
, except for a corner case described at the end of this post.Here is a typical use case:
It's obviously not something we want to encourage, in particular because the extra fields could become unreachable from the code but the GC will not be able to collect them. But I would be surprised if there's not at least one piece of code using a trick like that in the wild.
Currently, if we except the issues with collecting unreachable values (and potential extra memory usage) there doesn't seem to be anything in the compiler relying on the fact that runtime values are not bigger than their type would suggest, so the above code should work as expected. But there is (almost, see end of the post for details) nothing that allows one to produce a value whose runtime size is bigger than the size for its type without the
Obj
module either, so we're still in a position where we can forbid it.So we were left wondering: should we explicitly support the feature ? Explicitly forbid it ? Do nothing ?
The flambda 2 code is moving towards the second solution; in theory it means that we could treat code that is currently legal (for example,
let f (x, y) = ... in f (Obj.magic (0,1,2))
) as if it was unreachable. In practice this interpretation is most useful in cases likelet option_of_error = function | Ok x -> Some x | Error _ -> None
, where the strict semantics allow us to replace the allocation ofSome x
by the input value (see also #8958 for a version based on flambda 1). In a less strict semantics this could silently keep more values alive, so would not be obviously beneficial or even correct.However, supporting mismatching sizes could be useful to implement new features/optimisations. For example, an explicit no-cost coercion operator for modules (
Set.Make(MyModule :> Set.OrderedType)
). There were also a few similar opportunities that arose during a past internship about identity functions.To conclude, here is an example that illustrates the only case I'm aware of where the compiler can produce values with mismatched sizes for genuine code:
The example prints
true
in all cases in bytecode and with flambda, but printsfalse
in the first two cases with closure. This is because the special compilation scheme for compilation unit module blocks in Closure may append extra fields at the end of the module block, after the ones in the signature (in this case the value ofy
).Beta Was this translation helpful? Give feedback.
All reactions