Open lwchkg opened 7 years ago
Anyway, here are the contents of the source files:
index.js
// @flow
import {A} from "./a.js";
import {B} from "./b.js";
const a = new A(null);
const b = new B(a);
console.log("A = ", a);
console.log("B = ", b);
a.js
//@ flow
import type {B} from "./b.js";
export class A {
b: ?B;
constructor(b: ?B) {
this.b = b;
}
}
b.js
// @flow
import type {A} from "./a.js";
// The following line causes the problem. Removine the line and
// s/MaybeA/?A/ makes the file runnable.
type MaybeA = ?A;
export class B {
a: MaybeA;
constructor(a: MaybeA) {
this.a = a;
}
}
I have edited the generated b.js
a bit and it seems to fix the problem:
var MaybeA = _tcomb2.default.maybe(_a.A, "MaybeA");
becomes a lazy evaluating function with closure:
var MaybeA = function() { var _ty; return function() { if (!_ty) _ty = _tcomb2.default.maybe(_a.A, "MaybeA"); return _ty; } }();
And of course
_assert(a, MaybeA, "a");
becomes
_assert(a, MaybeA(), "a");
Flow allows for circular dependencies at the type-level. However babel-plugin-tcomb needs to reify those types at the value level so avoiding circular dependencies in the first place seems the best option.
I'm not sure that a lazy definition like that would handle all the use cases
Flow allows for circular dependencies at the type-level. However babel-plugin-tcomb needs to reify those types at the value level so avoiding circular dependencies in the first place seems the best option.
Sadly those circular dependencies are not always removable. Consider the case a parent object that owns a few children, and each children has a weak reference to the parent. This is a circular reference, but not a bad programming habit at all.
I'm not sure that a lazy definition like that would handle all the use cases. No. By adding
export b_singleton = new B(null);
at the end ofb.js
, the lazy evaluations will be immediately invoked and still crash. However, declarations alone will not be able to crash the lazy definitions, be it type, function or class.
Anyway, unless we can put the definition of A in another file, we can't really be sure that the definitions will be loaded before it is executed. But I don't think we can do this with babel.
How to reproduce:
yarn install
yarn compile
(without tcomb)yarn execute
yarn compile-debug
(with tcomb)yarn execute
.Expected result Step 7 produces the same result as step 5.
Actual result Crashed. Here's the log (also in the ZIP file):
What caused the crash?
index.js
importsa.js
,a.js
"import type"b.js
, andb.js
"import type"a.js
. There's atype
statement in b.js, using a type ina.js
, but the type is not available yet because this is a circular import.