The two language paths of this tutorial teach the same Lingua Franca
concepts with the same labs, exercises, and checkpoints. If you finished
the labs in one language, you can redo any lab in the other by translating
only the reaction bodies and a handful of API calls. Everything at the LF
level (reactors, ports, connections, timers, actions, modes, deadlines,
federated) is identical in both paths.
- All LF syntax:
reactor,main reactor,federated reactor, ports,state, parameters,timer,logical action,physical action, connections (includingafter), modes withreset/historytransitions, anddeadline(...)clauses. - Target properties used in the labs:
timeout,keepalive. - The commands:
lfc src/labN/Program.lfandbin/Program, run from theCorPythonproject root. - The generated layout:
bin/,src-gen/, and (Lab 8)fed-gen/with the RTI, the per-federate programs, and thebin/<Name>launch script. - The observable behavior of every lab program, including the tags, microsteps, and deadline patterns in the expected outputs. (Lab 7 Part B uses a different grid size per language so that pass times suit each runtime's speed, so the reported path lengths differ; the anytime behavior is the same.)
C is typed; Python is not. The same declarations look like this:
| Declaration | C | Python |
|---|---|---|
| Input port | input x: int |
input x |
| Output port | output y: int |
output y |
| State variable | state count: int = 0 |
state count = 0 |
| Time parameter | period: time = 1 s |
period = 1 s |
| Typed action | logical action a: int |
logical action a |
One naming difference: in is a reserved word in Python, so the Python
labs name input ports inp where the C labs use in.
| Purpose | C | Python |
|---|---|---|
lf_print("v %d", x); |
print(f"v {x}") |
|
| Read an input | x->value, x->is_present |
x.value, x.is_present |
| Write an output | lf_set(y, v); |
y.set(v) |
| State / parameter | self->count |
self.count |
| Schedule an action | lf_schedule(a, d); |
a.schedule(d) |
| Schedule with payload | lf_schedule_int(a, d, v); |
a.schedule(d, v) |
| Action payload | a->value |
a.value |
| Elapsed logical time | lf_time_logical_elapsed() |
lf.time.logical_elapsed() |
| Logical time | lf_time_logical() |
lf.time.logical() |
| Physical time | lf_time_physical() |
lf.time.physical() |
| Elapsed physical time | lf_time_physical_elapsed() |
lf.time.physical_elapsed() |
| Current tag | lf_tag().time, lf_tag().microstep |
lf.tag().time, lf.tag().microstep |
| Set the next mode | lf_set_mode(MovingUp); |
MovingUp.set() |
| Request a clean stop | lf_request_stop(); |
lf.request_stop() |
| Mid-reaction deadline check | lf_check_deadline(self, true) |
self.check_deadline(True) |
| Time literals in body code | MSEC(250), SEC(1) |
MSEC(250), SEC(1) |
Time values are 64-bit nanosecond integers in both targets. In C, print
them with %lld after casting to long long; in Python they are ordinary
ints.
Both targets use preamble {= ... =} blocks, but they hold different
things:
- C:
#includedirectives, helper functions, and thread functions. A file-level preamble may only declare symbols shared across reactors; definitions go inside a reactor's preamble. Threads uself_thread_tandlf_thread_create(...)from"platform.h", and sleeping useslf_sleep(...)from the same header. - Python:
importstatements and helper functions. Anything defined in a reactor's preamble is reached throughself: afterimport threading, useself.threading.Thread(...); a preamble functiondef helper(self, ...)becomes the methodself.helper(...). Threads that block oninput()are created withdaemon=Trueso the process can exit while they are blocked; sleeping usesself.time.sleep(seconds)(note: seconds, not nanoseconds).
The keyboard pattern used in Labs 5, 6, and 8 is the same in both languages: a thread blocks on standard input and schedules a physical action for each line; only the thread-creation and read calls differ.
The LF handbook describes the mid-reaction deadline check,
lf_check_deadline(), as implemented only for the C target. In practice,
the Python runtime shipped with LF v0.13.0 provides the equivalent method
self.check_deadline(invoke_handler), and the Python Lab 7 uses it. If
you need a portable fallback in Python, compare lf.time.physical()
against lf.time.logical() plus your budget; that is an ordinary
target-language computation, not an LF feature.
cdinto the other project root (CorPython); the lab layout and README structure are identical.- Read the same lab README there; commands, exercises, and checkpoints match, with the code snippets already translated.
- When you translate your own reaction bodies, work through the tables above; almost every line maps one to one.
- Expect the same output, with two caveats: the Python runtime prints a
Using Python versionbanner, and in federated runs the Clf_printlines carry aFed N (...)prefix while Pythonprintlines do not.