4 ms·
Unusual concept. Will split my thoughts on implementation and adoption (in regards to design). Implementation-wise: Tried myself something similar. One languag
by forgotpwd16 9mo ago
Unusual concept. Will split my thoughts on implementation and adoption (in regards to design).
Implementation-wise: Tried myself something similar. One language (same core & lib & built-ins) with 2 front-ends that had different syntax and, but similar, semantics. (Didn't go far though.) An issue is not favoring one over the other. Inevitably, in a meta way, you'll if decide to self-host since will've to pick one form to do it. Also, having multiple co-existing forms in same file may complicate tooling.
About the last part, most similar things I've seen are: (i) Perl Mojo's embedded templates which can be included in same file with source code, (ii) Racket's #lang multi-file which allows combining, well, multiple files (thus also use different #lang directives) in same file.
Adoption-wise: It's in a weird position for widespread adoption. There's strong preference towards using a single language which splits into 2 branches: (1) using single language across every layer (basically Rust/Zig), (2) using high-level language with native-competive performance (Python+numpy, jax, etc / JS+ultrafast JIT / Julia).
Currently you target both (one base language) and none (different syntax/semantics). Could move towards an hybrid approach instead by having one syntax and high-level / low-level forms (uncertain what distinguishes kernel/baremetal currently). So some functionality may end up showing differently in the 2 cases to be more acceptable by both camps. This will probably also simplify tooling creation/maintenance.
Of course, since the project is quite experimental in nature, keeping it current way is interesting and very acceptable.
TL;DR Yes (~templating) - Yes (complexity, lower potential adoption) - No (unusual, experimental)
- JhonPork 9mo agoThis is fair feedback, and you’re pointing at the main tradeoff intentionally. One clarification that might help: Falcon isn’t multiple frontends or multiple grammars in the usual sense. The parser accepts all code into a single AST, but during IR lowering the compiler is invoked with exactly one active profile. Nodes whose profile doesn’t match are not lowered to IR at all — they’re rejected before borrow checking, optimization, or codegen. From the compiler’s point of view, the other profiles never existed. There’s no runtime guard, no macro-style inclusion, and no shared assumptions leaking across profiles. The goal isn’t to let people freely mix levels like unsafe {} in Rust, but to make domain boundaries explicit and enforceable. Kernel/baremetal code has fundamentally different invariants (no heap, no panic, different aliasing rules), and soft escape hatches tend to blur those over time. That said, I agree this does increase tooling complexity and may reduce adoption. This is very much an experiment to see whether hard separation + single IR is a better tradeoff for certain projects than one-size-fits-all semantics. Appreciate the comparison examples — they’re useful references.