WebAssembly / WebAssembly/component-model

Subtyping rules allow losing information

Open
#67 9 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
WebAssembly
Stars
1.4k
Forks
130
Avg merge
2d 1h
Merged PRs (30d)
15

Description

My current interpretation of the subtyping rules is that the intention is to be primarily useful when connecting two components together within the same component. When a function call happens across these components my presumption is that the value provided must be a subtype of the value being received and an implementation of the component model ensures that at runtime everything lines up nicely.

Given the current rules for subtyping, though, it seems like there's inconsistency in what the intention of subtyping is. Naively I would expect that all the "information" provided by the caller can be received by the callee. For example that's why u8 is a subtype of u64 since if you get handed 8 bits but want 64-bits no information is lost during the conversion. Conversely u64 is not a subtype of u8 since information could be lost when passed.

Some rules, however, allow losing information. For example:

  • Everything is a subtype of unit, meaning that anything can be arbitrarily discarded if the receiving type is unit. I think this means that a function which previously returned nothing could suddenly start returning something (since I think the order of subtyping checks are switched there?)
  • Superfluous fields are dropped in record types, in that if you're given a record of two fields but only want a record one field I believe the second one is dropped.
  • A tuple is a subtype of any of the concrete types in the tuple itself, meaning all tuple fields can be dropped.
  • Superfluous function parameters are dropped.

This is all my current understanding which could very well be wrong though. The subtyping rules are not formalized at this time so I'm making what may be a good deal of inferences based on the current notes in the repository.

If my understanding is correct though personally I view dropping information during subtyping as pretty bad gotcha waiting to happen. For example:

  • A function which returns a fallible result indicating success or failure could always be imported as a function which returns unit. My experience in Rust and C is that every function which returns a fallible result needs to have some action taken by the caller. Even if the action is to ignore the error it's best to force all callers to do that than to silently allow ignoring the result. From an API evolution perspective as well this makes it seemingly backwards-compatible to start returning a fallible result when previously a function was infallible but from a software engineering perspective that seems like something that no one would ever actually want to do.
  • Dropping function parameters allows a caller to declare many different kinds of function signatures for an imported function. I'm not sure though what the use case is for supporting declaring a function taking more parameters than it actually takes, or on the other end what the use case is for dropping function paramaters from a preexisting function. From the caller's perspective I'd expect all function parameters to be taken into account and if one is silently ignored that seems like something that would be very difficult to diagnose.
  • My current understanding is that the general idea is that optional function parameters can be added to a function backwards-compatibly, but with the current requirement that names must match in-order and additionally superfluous parameters are ignored then that can't actually be done because if an optional parameter were added to the end of the parameter list then that would break clients passing too-many-arguments with different names.

Personally I don't think the subtyping rules should allow for losing information. I don't fully understand all the currently intended use cases of subtyping but if a use case requires one of the subtyping rules that loses information then I think the same functionality should be sought out through other means or similar. Otherwise the ability to silently lose information here seems like it will be a strong source of bugs in components not realizing data is lost, bugs introduced silently in "semver-compatible updates" to components which take consumers time to realize, or perhaps even security issues in hosts due to how complex the subtyping rules are.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the repository's current notes and rules for subtyping, especially the cases involving unit, records, tuples, and function parameters. Determine whether the intended rules permit information loss, then document or revise the rules so the chosen behavior and its compatibility implications are explicit.

Written by the indexing model from the issue text.

Assessment

Tech stack
wasm
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.