DEV Community

COMMENTERTHE9
COMMENTERTHE9

Posted on • Originally published at cx-lang.com

Cx Dev Log — 2026-06-27

Result just crossed a major compiler boundary in Cx, marking a significant step forward in our error handling journey. Two key commits have successfully integrated the packed-i128 representation and introduced the ? (Try) operator within the JIT pathway. Let's explore how these changes shape the overall architecture and what they mean for developers working with Cx.

The packed-i128 representation

Storing Result as a packed i128 turned out to be an interesting technical challenge. We split the i128 into a tag and a payload, with the high 64 bits reserved for the tag (Ok = 0, Err = 1) and the low for the payload. The goal was to maintain clear separation without arithmetic packing, which would risk sign-extension messing up the tag when handling negative payloads. Instead, we opted for a memory round-trip approach: allocate, store, and then load both parts into a single i128. This method is mechanically heavier but it confidently preserves data integrity—an essential choice.

One key safeguard is a canary fixture named t_result_ok_negative.cx, ensuring negative payloads don't corrupt the tag. Any future attempt to optimize this away would trigger the test.

On the Cranelift front, we had to tweak the settings a bit with enable_llvm_abi_extensions in host_boundary.rs to handle i128 arguments correctly. It’s a small but critical adjustment to maintain byte-for-byte output consistency between JIT and interpreter.

The ? operator

Bringing the expr? operator into the picture with D2.4b required an ingenious unpacking process. Here, the packed i128 unpacks using result_unpack, allowing us to branch on the tag. For an Ok tag, execution proceeds by narrowing the payload back into its original form. For an Err, we return the entire i128 early, preserving error data consistency to the caller.

Importantly, Cx's semantic analyzer ensures ? is context-appropriate—enforcing its use only within Result-returning functions. This preemptive check simplifies the lowering and avoids unnecessary runtime consistency checks.

It's worth noting that the Result usage is bounded by T's ability to fit within a single i64 word. While this decision limits nested Results, it keeps us honest about representation constraints and prevents unknown behavior, clearly marking where further work lies.

Example suite rewrite

Apart from the core changes, the examples/ directory got a fresh, comprehensive rewrite. The examples now include more intuitive code patterns, richer demonstrations, and polished documentation. The error_handling.cx example stands out, showcasing the Result and ? operator now viable due to these backend improvements. These changes, though uncommitted, prepare the ground for developers to see these new capabilities in action, adding roughly 280 lines across the suite.

What's next

Our upcoming focus is on D2.4c, addressing equality routing for Result types. While assert_eq functions effortlessly for Result due to i128 equality on Ok tags, Err comparison will rely on cx_str_eq for fairness on strings. These finer routing details are pivotal for robust error-type handling.

Meanwhile, the example documentation overhaul is pending commit. The error-handling example, central to our recent changes, waits in the wings for the new commits to merge into main, already 24 commits behind the action.

Looking ahead, our roadmap includes tackling dynamic strings (R6) and DotAccess in compound forms to complete Phase 11. Parity benchmarks have already improved with 229 tests passing out of 287 on submain, whereas main lingers a bit behind.


Follow the Cx language project:

Originally published at https://cx-lang.com/blog/2026-06-27

Top comments (0)