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

Incorporate generative RTT #86

Closed
wants to merge 1 commit into from
Closed

Conversation

RossTate
Copy link
Contributor

Thanks to a number of discussions, I now have enough understanding of the expected conventions for this proposal to suggest a modest revision that should address a number of open questions.

First, the proposal already has in place an expectation to use run-time type information, RTT(I)s. One thing that was unclear is what precisely the semantics of RTTIs should be. For example, if $t1$ is a subtype of $t2, should an anyref with the RTT (rtt.get $t1) be castable to a $t2 via (rtt.get $t2)? According to the current semantics, the answer is no—the cast should only succeed if the two types are exactly the same. This is good for performance, but it did bring into question how modules should share values via anyref since it means they have to agree exactly on what run-time types to use.

The expectation now, though, is that coordinated "share-nothing" module communication will be done via Interface Types. Furthermore, in #85, we agreed that for uncoordinated/heterogeneous communication (say via anyref), it is important for correctness that modules be able to distinguish their values (via generative tags, like with exceptions) from those of other values (even if they happen to have the same structure).

Furthermore, in WebAssembly/proposal-type-imports#7, we came to the conclusion that, in order to prevent client modules from inspecting the internals of abstract exported types, we need to be able to guarantee that exported values can only be cast to a target (structural) type if the module also exports its own (generative) rtt for the target type.

Altogether, this indicates that rtts should be generative. On top of that, I was able to go through the overview and easily switch all the examples to generative RTTs, so the adjustment seems to be compatible with the known usage patterns. The adjustment required little change to the instructions, with the most significant being that rtt.sub semantics are now to always generate a new rtt rather than to always reproduce the same rtt with the same inputs.

My hope is that, by pinning answers to some of the major open questions, this gets us all on the same page as to what this proposal entails and how it should be expected to be used and implemented.

@tlively
Copy link
Member

tlively commented Mar 29, 2020

Can you briefly explain what "generative" means in this context and what alternatives it differentiates from?

Comment on lines -297 to +293
- multiple invocations of this instruction with the same operand yield the same observable RTTs
- each invocation of this instruction yields a distinct RTT
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tlively: Here is the most important change (along with the matching change in rtt.get to rtt.new). An "applicative" system returns the same value when given the same inputs (previous semantics), whereas a "generative" system returns a new value distinct from all previous values (new semantics).


* `rtt.sub <typeuse>` returns the RTT of the specified type as a sub-RTT of a given parent RTT operand
- `rtt.sub t : [(rtt t')] -> [(rtt t)]`
- iff `t <: t'`
- multiple invocations of this instruction with the same operand yield the same observable RTTs
- each invocation of this instruction yields a distinct RTT
- this is a *constant instruction*
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this assertion was already present but wasn't true. For an applicative semantics, one must canonicalize the structure of the type (which is not constant time), hash it (again not constant time), and then use a host-global concurrent hash map to get the canonical rtt for the type (requiring another non-constant-time equality comparison). When the type is known it compile time, which is currently the case for this proposal, then all of that can be done at compile time and the instruction replaced with the precomputed rtt, which is where the assertion that this instruction is constant time comes from. However, the proposal also recommends adding parametric polymorphism later on, which will introduce type parameters that the type in rtt.get can refer to, in which case all of this will have to be done at run time and the instruction will no longer be constant time. With the generative semantics, this is constant time even in the presence of type variables.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Constant instruction" is spec terminology that has nothing to do with constant time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks for the correction and the link!

@rossberg
Copy link
Member

The current docs do not incorporate generative types yet, neither statically nor dynamically. If we add nominal types then of course we'd also want to add generative RTTs. However, that does not eliminate the need for non-generative RTTs, for the same reason as with static types.

So such a change should add rtt.new, not replace rtt.get. FWIW, having both was in my slides on an alternative design with mere tags (where they were called tag.new and tag.canon) that I didn't get to show at the meeting (but you saw the slides, I think).

@RossTate
Copy link
Contributor Author

However, that does not eliminate the need for non-generative RTTs, for the same reason as with static types.

Could you give some examples? In your talk at the in-person meeting, you advocating for removing anything from the MVP that could reasonably be expressed without it. I removed rtt.get because every example could reasonably be expressed without it. (The same was not true for rtt.new due to the rationale above, particularly WebAssembly/proposal-type-imports#7.)

rossberg pushed a commit that referenced this pull request Feb 24, 2021
* Fix expected trap messages.

The spec interpreter says "element segment dropped", rather than
"elements segment dropped".

* Fix "zero len, but dst offset out of bounds" test.

Fix this test to test what it's comment says it's testing.

* Add more tests for zero-length operations.

* Update the Overview text to reflect the zero-length at-the-end semantics.
rossberg pushed a commit that referenced this pull request Feb 24, 2021
Change the test generators to use `ref.func` and remove `passive`.

At some point we'll want to remove the generators, but for let's try to
maintain them.
@tlively
Copy link
Member

tlively commented Oct 17, 2022

I'll close this PR since we won't be including RTTs of any kind in the MVP.

@tlively tlively closed this Oct 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants