I am developing a tool that generates dart code and I am facing this runtime error when executing a program having a circular dependency.
file.dart:xx:xx: Error: Constant evaluation error:
this.b = const B(),,
^
file:xx:xx: Context: Constant expression depends on itself.
this. A = const A(),
Here is a simplification of the program I am executing:
class A {
final B b;
const A({
this.b = const B(),
});
}
class B {
final A a;
const B({
this.a = const A(),
});
}
As you can see there is a circular dependency between A and B.
I tried dropping the const keyword as:
class A {
final B b;
A({
this.b = B(),
});
}
class B {
final A a;
B({
this.a = A(),
});
}
But instead, I am getting a compile time error:
The default value of an optional parameter must be constant. dart(non_constant_default_value)
Do you have an idea how to handle this type of issue? Or is there an equivalent of forwardref in Dart?
At the current state of dart, it is not possible to avoid this circular dependency. I ended restricting this case. If the input has a circular dependency, it is normal that the output will have it.
Your approaches don't work because when you construct A()
, it will construct a B()
which will construct A()
which will construct B()
, ad infinitum. You need to break the infinite recursion loop.
If you want a single instance of A
and a single instance of B
to have references to each other, you will need to have one of them pass a reference to itself instead of letting the other constructor create a new instance of the initial type. You can't pass this
in an initializer list (this
is not yet valid at that point), so it must be done in the constructor body, and the initialized final
members will need to be late
. The constructor body also means that both classes cannot have const
constructors.
If you want const
constructors because you want to have A()
and B()
as default arguments, the typical approach is to use null
as a default.
class A {
late final B b;
A({B? b}) {
this.b = b ?? B(a: this);
}
}
class B {
late final A a;
B({A? a}) {
this.a = a ?? A(b: this);
}
}