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

Document $Subtype and $Supertype #6887

Closed
wants to merge 1 commit into from

Conversation

aij
Copy link

@aij aij commented Sep 13, 2018

Short description taken from type_annotation.ml and formatted.

Unsoundness warnings per those in objects.md and functions.md

Close #6886

Short description taken from type_annotation.ml and formatted.

Unsoundness warnings per those in objects.md and functions.md
Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

fishythefish has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@wchargin
Copy link
Contributor

Your helpful example at #6886 demonstrates that it is absolutely the
case that $Subtype/$Supertype can be used in unsound ways. But I’m
trying to understand whether these type constructors are always
unsound, or whether it’s just easy to use them in cases that induce
unsoundness—especially in light of the rather aggressive warning
introduced by this PR (not that I object!). Perhaps you can help me
understand?

For instance, consider the following function:

/**
 * Merge maps without mutating the arguments.
 *
 * Merges multiple maps, returning a new map which has every key from
 * the source maps, with their corresponding values. None of the inputs
 * are mutated. In the event that multiple maps have the same key, an
 * error will be thrown.
 */
export function merge<K, V>(
  maps: $ReadOnlyArray<Map<$Subtype<K>, $Subtype<V>>>
): Map<K, V> {
  // Implementation elided (available upon request). It has no casts.
}

The use of $Subtype, instead of fixed type parameters InK and InV,
is useful because it enables heterogenously typed maps with a common
upper bound:

    it("allows upcasting the type parameters", () => {
      const numberMap: Map<number, number> = new Map().set(1, 2);
      const stringMap: Map<string, string> = new Map().set("one", "two");
      type NS = number | string;
      const _unused_polyMap: Map<NS, NS> = MapUtil.merge([
        numberMap,
        stringMap,
      ]);
    });

When I wrote the type for the above function, I certainly didn’t think
of it as “opting out of the type system”; rather, it’s just expressing
the natural constraint.

It seems to me that this function is sound, despite the use of
$Subtype, similar to how a function (x: Array<any>) => x.length is
sound. Do you agree? Is there a nice way to characterize under which
circumstances these types can be used safely?

@zeorin
Copy link

zeorin commented Oct 23, 2018

Does this mean that $Subtype<() => mixed> is the same as Function and $Subtype<{}> is the same as Object?

@dsainati1
Copy link
Contributor

This pull request is redundant now, since these utilities have been deprecated.

@mvitousek mvitousek closed this Feb 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants