The interconnection pattern for a collection of reactors can form a cycle, but some care is required. Consider the following example:
c
cpp
py
rs
ts
target C;
reactor A {
input x:int;
output y:int;
reaction(x) -> y {=
// ... something here ...
=}
}
reactor B {
input x:int;
output y:int;
reaction(x) {=
// ... something here ...
=}
reaction(startup) -> y {=
// ... something here ...
=}
}
main reactor {
a = new A();
b = new B();
a.y -> b.x;
b.y -> a.x;
}
target Cpp;
reactor A {
input x:int;
output y:int;
reaction(x) -> y {=
// ... something here ...
=}
}
reactor B {
input x:int;
output y:int;
reaction(x) {=
// ... something here ...
=}
reaction(startup) -> y {=
// ... something here ...
=}
}
main reactor {
a = new A();
b = new B();
a.y -> b.x;
b.y -> a.x;
}
target Python;
reactor A {
input x;
output y;
reaction(x) -> y {=
# ... something here ...
=}
}
reactor B {
input x;
output y;
reaction(x) {=
# ... something here ...
=}
reaction(startup) -> y {=
# ... something here ...
=}
}
main reactor {
a = new A();
b = new B();
a.y -> b.x;
b.y -> a.x;
}
target Rust;
reactor A {
input x:u32;
output y:u32;
reaction(x) -> y {=
// ... something here ...
=}
}
reactor B {
input x:u32;
output y:u32;
reaction(x) {=
// ... something here ...
=}
reaction(startup) -> y {=
// ... something here ...
=}
}
main reactor {
a = new A();
b = new B();
a.y -> b.x;
b.y -> a.x;
}
target TypeScript
reactor A {
input x:number
output y:number
reaction(x) -> y {=
// ... something here ...
=}
}
reactor B {
input x:number
output y:number
reaction(x) {=
// ... something here ...
=}
reaction(startup) -> y {=
// ... something here ...
=}
}
main reactor {
a = new A()
b = new B()
a.y -> b.x
b.y -> a.x
}
This program yields the following diagram:
The diagram highlights a causality loop in the program. At each tag, in reactor B, the first reaction has to execute before the second if it is enabled, a precedence indicated with the red dashed arrow. But the first can't execute until the reaction of A has executed, and that reaction cannot execute until the second reaction B has executed. There is no way to satisfy these requirements, so the tools refuse to generated code.
Frequently, a program will have such cycles, but you don't want a logical delay in the loop. To get a cycle without logical delays, the reactions need to be reordered, as shown below:
c
cpp
py
rs
ts
target C;
reactor A {
input x:int;
output y:int;
reaction(x) -> y {=
// ... something here ...
=}
}
reactor B {
input x:int;
output y:int;
reaction(startup) -> y {=
// ... something here ...
=}
reaction(x) {=
// ... something here ...
=}
}
main reactor {
a = new A();
b = new B();
a.y -> b.x;
b.y -> a.x;
}
target Cpp;
reactor A {
input x:int;
output y:int;
reaction(x) -> y {=
// ... something here ...
=}
}
reactor B {
input x:int;
output y:int;
reaction(startup) -> y {=
// ... something here ...
=}
reaction(x) {=
// ... something here ...
=}
}
main reactor {
a = new A();
b = new B();
a.y -> b.x;
b.y -> a.x;
}
target Python;
reactor A {
input x;
output y;
reaction(x) -> y {=
# ... something here ...
=}
}
reactor B {
input x;
output y;
reaction(startup) -> y {=
# ... something here ...
=}
reaction(x) {=
# ... something here ...
=}
}
main reactor {
a = new A();
b = new B();
a.y -> b.x;
b.y -> a.x;
}
target Rust;
reactor A {
input x:u32;
output y:u32;
reaction(x) -> y {=
// ... something here ...
=}
}
reactor B {
input x:u32;
output y:u32;
reaction(startup) -> y {=
// ... something here ...
=}
reaction(x) {=
// ... something here ...
=}
}
main reactor {
a = new A();
b = new B();
a.y -> b.x;
b.y -> a.x;
}
target TypeScript
reactor A {
input x:number
output y:number
reaction(x) -> y {=
// ... something here ...
=}
}
reactor B {
input x:number
output y:number
reaction(startup) -> y {=
// ... something here ...
=}
reaction(x) {=
// ... something here ...
=}
}
main reactor {
a = new A()
b = new B()
a.y -> b.x
b.y -> a.x
}