v4.5.0
Verbatim type & value passthrough — closes the last gap between the documented “Frame has no type system” contract and what codegen actually did.
Frame’s contract is that type annotations and initializer values pass through to the generated code verbatim — you write your target language’s own type names and literals, and framec does not parse, validate, or translate them. This release makes the compiler honor that contract uniformly: it removes the residual per-backend type-alias tables and the state-variable “portable init” value wrapping that still contradicted it, and fixes a float-literal corruption bug that those layers were hiding. This release has breaking hard-cuts; all are mechanical to fix and Frame is pre-public-beta, so no published program is affected. See the migration guide.
Highlights
- Type annotations emit verbatim on every backend (#61). The leftover
alias tables —
int→i64,str→String,float→f64, etc. — are gone from the Rust pipeline (rust_system.rs/runtime.rs, the typed-compartment path, and the return-boxing cast shim) and from themap_type/convert_typefunctions on the remaining backends. You now write your target’s own type names (i64,String,Vec<i32>,std::string,Array, …) and they reach the generated code unchanged. Machinery types (the generic stacks, untyped event params) are unaffected. - State-variable initializers emit verbatim (#59, #62). State-var init values
now carry raw text and are emitted exactly like domain-field initializers —
framec no longer parses them into an AST and re-serializes them. This fixes a
real bug where a whole-number float (
$.x: f64 = 0.0) was truncated to an integer literal (0), producing uncompilable Rust (and wrong values on every typed target). The per-target “portable init” wrapping (""→String::from("")etc.) is removed in the same change — write your target’s native init value. - The 17-language differential matrix is green end-to-end on the verbatim contract (the test corpus and per-language guides were updated to native type names and init values to match).
Breaking changes
See the migration guide for the canonical→native table and worked before/after.
- Type annotations are no longer aliased. A source that wrote a Frame-canonical
name (
: int,: str,: float) and relied on framec mapping it to the target’s native type now emits that name verbatim. On targets where the canonical name is native (intin C/Go/Java/C#/Python,boolin Rust/C/C++) nothing changes; where it isn’t — notablystreverywhere, andint/floaton Rust — you must write the native name (String/i64/f64, …). - State-variable init values are no longer wrapped. A
String-typed state var initialized with a bare""now emits""(a&stron Rust) instead ofString::from(""). Write the native init value:String::from("")on Rust,std::string("")on C++,""on dynamic targets.
Action required
Sources already written in native type names and native init values generate identical output to 4.4.x and need nothing. If you used Frame-canonical aliases or relied on portable-init wrapping, rewrite the affected annotations/values to your target’s native spelling — see the migration guide for the per-target table.