Flow: [mixed type] Supertype bug

Created on 10 Apr 2016  路  8Comments  路  Source: facebook/flow

From the doc:

The mixed type is a supertype of all types.

So:

const foo: Object = {};
const bar: mixed = foo;

No errors!

OK, since mixed is the Supertype of 'Object'.

But:

const foo: Array<Object> = [{}, {}];
const bar: Array<mixed> = foo;
144: const bar: Array<mixed> = foo;
                      ^^^^^ mixed. This type is incompatible with
143: const foo: Array<Object> = [{}, {}];
                      ^^^^^^ object type

WTF ??? Now mixed is not the supertype of Object ???

Most helpful comment

Wow Indeed I could not even supposed Object acts as any (a kind of wildcard/bypass).

IMHO it's a bad behavior which mislead. I do not permit to emit a criticism you have made a great job with Flow, but please at least put the information in your website doc:

Object: The Object type is a supertype and subtype of all objects. That means Object is not the strict equivalent of the native/built-in Object type but is more similar to any.
To sum up: any is the sub/supertype of all scalars and objects whilst Object is the sub/supertype of all objects only (except for the Array type).

Array: IMPORTANT: Arrays are generics invariant.

Thanks for your support @samwgoldman.

All 8 comments

This is expected behavior. Your assertion that Array<B> should be a subtype of Array<A> if B is a subtype of A isn't true (Ed: corrected, per comment below). Phrased differently, your issue asserts that arrays are covariant. In fact, arrays are invariant.

Read-only arrays _would_ be covariant, but since arrays are mutable in JS, they are invariant in Flow, which prevents unsound code like the following:

class A {}
class B extends A {}
var bs: Array<B> = [];
var as: Array<A> = bs;
as.push(new A); // this would be bad!

OK thanks for the explanation, it make sense now.

But I never said this:

Your assertion that Array<B> should be a subtype of Array<A> if A is a subtype of B isn't true."

Instead:

Your assertion that Array<B> should be a subtype of Array<A> if A is a supertype of B isn't true."

You're right鈥擨 misspoke. Thanks for the correction!

No prob.
You welcome :)

@samwgoldman thanks for the explanation! it seems to be the general rule for all the languages that only read-only types can be covariant

Hum...

OK, following your explanation:

class Foo{}
class Bar extends Foo{}

const a: Array<Bar> = [];
const f: Array<Foo> = a;
164: const f: Array<Foo> = b;
                    ^^^ Foo. This type is incompatible with
163: const b: Array<Bar> = [];
                    ^^^ Bar

Alright ! Bar inherits from Foo, arrays are invariant, error is legitimate.

But:

const s: Array<String> = [];
const o: Array<Object> = s;
o.push({ a: 'dat fail :)' });// Holy hell !!!
No errors!

String inherits from Object but everything is OK ???
This is an inconsistent behavior with built-in Type ?

Nice observation! The Object type is a supertype and subtype of all objects, similar to any. So Array<Object> is compatible with Array<String>, since Object <: String _and_ Object :> String.

Aside, I wish we had named Object something like AnyObject instead, and made Object more specifically the type of new Object with methods like toString but nothing else.

Wow Indeed I could not even supposed Object acts as any (a kind of wildcard/bypass).

IMHO it's a bad behavior which mislead. I do not permit to emit a criticism you have made a great job with Flow, but please at least put the information in your website doc:

Object: The Object type is a supertype and subtype of all objects. That means Object is not the strict equivalent of the native/built-in Object type but is more similar to any.
To sum up: any is the sub/supertype of all scalars and objects whilst Object is the sub/supertype of all objects only (except for the Array type).

Array: IMPORTANT: Arrays are generics invariant.

Thanks for your support @samwgoldman.

Was this page helpful?
0 / 5 - 0 ratings