-
Notifications
You must be signed in to change notification settings - Fork 7
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
[overview] Expand explanation; add private types #8
Conversation
proposals/type-imports/Overview.md
Outdated
|
||
Type _exports_ are transparent by default. | ||
When using a type export to instantiate the import of another module, | ||
its full definition is therefor available to verify any import constraints. |
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.
typo: therefor -> therefore
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.
Fixed.
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.
(Sorry for the slow reply! I missed the notification.) I wonder if it's possible to achieve the requirements without requiring the extra boxing of reference values. I'm not sure I've thought through all the constraints, but it seems like we could achieve this by having:
deftype ::= <functype> | <privatetype>
(as in the PR)privatetype ::= private <heaptype>
(not a<valtype>*
)(ref (private $T)) </: (ref $T)
(analogous to the PR)- all the operations that are valid for
(ref $T)
are made valid for a(ref (private $T))
The net effect of the last bullet would be "almost subtyping" but without the ability to convert first-class (ref (private $T))
values into first-class (ref $T)
values. (Weird, I know; maybe you can help me find a better way to frame this.) Thus, creating a new private object would be just like creating a normal public object except the typeindex
would refer to a privatetype
instead of another kind of deftype
. So, specifically, a private function could be created by using the index of a privatetype
in the function
section and a private struct could be created with struct.new $PrivateType
.
Now, this doesn't work for i31.new
, since i31.new
doesn't have a typeindex
, so there would need to be some new boxing variant private.box_i31 : [i32] -> [(ref (private i31))]
which is unfortunate, but I don't see any way around boxing private i31
s when they can be upcast to anyref
and passed out to an untyped language. But at least every other reference type doesn't need to be boxed. (I think.)
WDYT?
Co-authored-by: Luke Wagner <mail@lukewagner.name>
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.
@lukewagner, re your suggestion:
privatetype ::= private <heaptype>
(not a<valtype>*
)
Yes, this is what I would have preferred to do. But then we'd need to pull in more stuff from the GC proposal, such as structs.
So instead, I was hoping that we can later reinterpret private type definitions in a way that unifies it with structs, see the section in the end. The main difference to the above would be that "private" ends up being a sort of flag on struct definitions(*), instead of a separate type constructor. That's slightly less nice from a decomposition point of view, but in neither case a separate allocation should be needed.
(*) And potentially others; a binary format hack could even backport the flag to func types, although I'm not sure what use case you have in mind.
(ref (private $T)) </: (ref $T)
(analogous to the PR)
Now this would imply that privatetype is a heaptype, not a deftype, I think?
Of course, you'd still need to be able to pass a ref $T
to somebody else (and receive it back), so you'd now need conversion functions between the two types. But why separate the reference types and require conversions? We'd still need to control availability of the conversions via scoping. With what I propose, scoping instead controls availability of accessors on the type directly. Outside the scope of the private definition it's still the same type, but you simply don't know anything about its definition -- basically, the usual semantics of abstract data types.
FWIW, this would work even if we separated private from struct. If you had
(type $S (struct (field i32)))
(type $P (private $S))
then you'd simple know (statically) that $P <: $S
inside the module but not outside. So all accessors would be applicable immediately.
@rossberg Ah hah, ok. I had seen the "reinterpret as a struct definition" bit, but I had interpreted it differently. Re-reading it now, I think I see what you're getting at. So to check my understanding: a type definition |
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.
Yes, exactly. I expanded the section to explain the desugaring more concretely. PTAL.
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.
lgtm, thanks for writing this up!
Co-authored-by: Luke Wagner <mail@lukewagner.name>
No description provided.