I wrote a DSL compiler this week for ZeroClaw . Not because I had to because the alternative was worse , my AI agent (ZeroClaw) needed to control hardware on a Raspberry Pi. The naive loop is agent calling tool or need to Rust written tools, you cross-compile, copy the binary, run it. Each iteration takes approximate 2 minutes for an agent that wants to experiment with hardware, that's death. So I built a hardware description language and a compiler for it ( just to understand DSL compilers and because I already architected the HAL interphase I knew what was goin on underneath). Example of what ZeroClaw/developer writes : servo CLAW_LEFT { pin: PA1 pwm_channel: 1 range: 0..180 frequency_hz: 50 } Four stages, hand-written, no parser-combinator crates lexer (finite automaton) → recursive-descent parser → semantic analyzer (collects all errors, doesn't fail fast) → a code generator that emits Rust for either STM32 or Raspberry Pi Then I embedded the compiler inside the agent. No subprocess. No file I/O. The agent generates HAL, the compiler validates it in-process, rppal toggles the pin. 2 minutes → under 1 millisecond. Same task. Six orders of magnitude. The lesson: when your tooling is the bottleneck, build even better tooling. Even when "better tooling" means writing a compiler at 2am.😂 What did i made? Answer : I built a Hardware DSL (Domain Specific Language) and a Compiler called zeroclaw-halc. The DSL: A simple way to write "code" that describes hardware (like LEDs, buttons, or motors) in plain text. The Compiler: A tool that reads that text, checks it for mistakes (like using the wrong pin), and turns it into actual hardware actions. Who can use it? Answer : Developers: They can use it to quickly generate the complex boilerplate code needed to start a new hardware project on Raspberry Pi or STM32. The ZeroClaw AI Agent: This is the big one. The AI now has a "manual" it can write. When it wants to control a light or a motor, it writes a .hal description, and my compiler tells it exactly how to do it. How does it help ZeroClaw? Answer: Before this, ZeroClaw was mostly "software." Now, it has a direct, safe link to the physical world: Safety: The compiler acts as a "safety guard." If the AI tries to use a pin that doesn't exist or conflicts with another part, the compiler catches it before anything breaks or burns out. Instant Control: ZeroClaw doesn't have to wait for a human to write code. It can generate its own hardware configuration on the fly and execute it in milliseconds on a Raspberry Pi. Multi-Platform: It makes ZeroClaw "hardware-agnostic." Whether you are using a Raspberry Pi or an industrial STM32 chip, the AI uses the same language to talk to both. thank you Sundai for the event..! #Rust #Compilers #EmbeddedSystems #EdgeAI #ZeroClaw 🦀
ZeroClaw Hardware DSL and Compiler
More Relevant Posts
-
I just pushed 309 new Rust modules to a public repo. 200k~ lines of code. 455 source files. All MIT licensed. Vitalis started as a Bytecode Alliance Cranelift experiment — a from-scratch JIT compiler to learn how native codegen actually works. 1,333 versions later, it compiles itself. Here's what's actually in the repo + repo in the comments publicly available: 𝗧𝗵𝗲 𝗰𝗼𝗺𝗽𝗶𝗹𝗲𝗿 → codegen.rs: 13,948 lines of hand-written Cranelift IR lowering → Full pipeline: Lexer → Parser → Type Checker → SSA IR → Native x86-64 → AOT compilation, cross-targets (AArch64, RISC-V), WASM backend → 6,742 tests passing 𝗦𝗲𝗹𝗳-𝗵𝗼𝘀𝘁𝗶𝗻𝗴 → 9 modules written in Vitalis that compile Vitalis → Lexer, parser, type checker, SSA IR, x86-64 emitter, register allocator, PE writer → Byte-identical output across independent runs → The compiler compiles the compiler. Verified. 𝗡𝗲𝘂𝗿𝗼𝗺𝗼𝗿𝗽𝗵𝗶𝗰 𝗰𝗼𝗺𝗽𝘂𝘁𝗶𝗻𝗴 → 15 modules, 360 native extern "C" functions → Spike engines, LIF neurons, Loihi simulation → SNN learning, hippocampal memory, quantum-neuro hybrids → Real algorithms, real FFI, callable from Vitalis programs 𝗘𝘃𝗼𝗹𝘂𝘁𝗶𝗼𝗻 𝗲𝗻𝗴𝗶𝗻𝗲 → Differential evolution, PSO, CMA-ES, NSGA-II, MAP-Elites → Meta-evolution via Thompson sampling → The compiler doesn't just compile — it searches for better ways to compile 𝗥𝗲𝘀𝗲𝗮𝗿𝗰𝗵 𝗺𝗼𝗱𝘂𝗹𝗲𝘀 → dream_compilation.rs — offline workload replay optimization → neural_parser.rs — ML-guided parse disambiguation → theorem_prover.rs — integrated correctness verification → software_organism.rs — self-healing code patterns These explore what compilers could become. Research, not production claims. The full history: v1–v44: Core compiler + JIT v45–v200: Type system, ownership, generics, stdlib v201–v300: Neuromorphic computing stack v301–v400: Bare-metal OS kernel experiment v401–v600: Evolution engine v601–v1333: Compiler-as-cognitive-system research This is a solo project. It's not Mozilla Firefox or rustlang stdlib. But the codegen is real, the self-hosting is verified, and the neuromorphics are functional implementations that call into native Rust. I'm proud of it and I want the Rust Foundation and Anthropic AI developer communities to explore it. #Rust #OpenSource #Compiler #ProgrammingLanguage #NeuromorphicComputing #JIT #MachineLearning #BuildInPublic #DeveloperTools Intel NVIDIA NVIDIA AI Claude Anthropic Google DeepMind Open Ai Labs
To view or add a comment, sign in
-
What is Lambda Syntax: [capture-list](parameters) -> return_type { body } When the compiler sees a lambda expression, it generates a unique, hidden Class (called a Closure Type). Lambdas: Are expressions, not declarations. They create a temporary "Closure" object. You can pass a lambda directly into another function It then creates a temporary Object of that class (the Closure). it is essentially a struct generated by the compiler. What is a "Closure" Object? The "Closure" is the physical manifestation of the lambda in memory. It is essentially a struct generated by the compiler. The Code: The lambda's body becomes the operator() (function call operator) of this hidden struct. A Functor is a struct that has been given the power to act like a function. In C++, you can overload almost any operator (+, -, *). When you overload the parentheses (), you are telling the compiler: "If someone puts parentheses next to an instance of this struct, execute this code." When the C++ compiler encounters the syntax name(arguments), it follows a specific hierarchy to resolve what that means: Is it a function? (No, is a variable/object). Is it a function pointer? (No, it's a class type). Does it have an operator()? (Yes! The compiler finds class::operator()). Once the compiler confirms that class has an overloaded (), it rewrites your high-level code into an explicit method call: e.g. obj(65.5) Internal Translation: obj.operator()(65.5) The Data: Every variable you put in the Capture List [ ] becomes a member variable of this hidden struct. This is why a lambda with a Capture List [factor] cannot be converted to a raw C function pointer—a raw pointer has no place to store the factor. In high-performance C++ and automotive systems (like ARM or x86_64 architectures), Registers are the fastest storage locations inside the CPU. Using a register for the this pointer is a standard optimization called a Calling Convention. Here is why the compiler chooses a register instead of RAM for this pointer. ## 1. Speed (The Primary Reason) Registers sit directly on the CPU core. Accessing a value in a register takes less than 1 nanosecond (typically 1 clock cycle). Registers: ~1 cycle L1 Cache: ~4 cycles Main RAM: ~100–300 cycles If the compiler used the Stack (RAM) to pass the this pointer: The caller would have to push the address onto the stack. The operator() would have to read it from the stack. This creates "traffic" on the memory bus. In automotive ECUs, where the CPU might be managing real-time engine timings or safety signals, reducing unnecessary memory traffic prevents bottlenecks and ensures deterministic timing.
To view or add a comment, sign in
-
In Rust, this compiler performance tweak that merges functions has to be handled with caution! ⚠️ 🦀 You’ve probably heard this advice before: “Small functions are cheap—don’t worry about them.” That’s usually true… until you start chasing performance. Because under the hood, every function call still has a cost: ▪️ jumping to another location in memory ▪️ setting up a stack frame ▪️ returning back So what if you could just… remove that call entirely? 𝐖𝐡𝐚𝐭 𝐢𝐬 𝐢𝐧𝐥𝐢𝐧𝐢𝐧𝐠? Inlining means the compiler replaces a function call with the actual code of that function. Instead of: ▪️ jumping to another function ▪️ then coming back …the compiler just puts the function’s code directly where it’s used. This removes the cost of calling the function and helps the compiler optimize better. 𝐇𝐨𝐰 𝐭𝐨 𝐮𝐬𝐞 𝐢𝐧𝐥𝐢𝐧𝐢𝐧𝐠 𝐢𝐧 𝐑𝐮𝐬𝐭 #[inline] fn add(a: i32, b: i32) -> i32 { a + b } --------------- #[inline(always)] fn fast(x: i32) -> i32 { x * 2 } --------------- #[inline(never)] fn slow() { println!("Not important for performance"); } --------------- #[𝐢𝐧𝐥𝐢𝐧𝐞] → “you can inline this” #[𝐢𝐧𝐥𝐢𝐧𝐞(𝐚𝐥𝐰𝐚𝐲𝐬)] → “please always inline this” #[𝐢𝐧𝐥𝐢𝐧𝐞(𝐧𝐞𝐯𝐞𝐫)] → “don’t inline this” These are hints to the compiler. 𝐖𝐡𝐲 𝐢𝐬 𝐢𝐭 𝐟𝐚𝐬𝐭𝐞𝐫? Inlining helps because: ▪️ No function call overhead ▪️ The compiler can better optimize the code ▪️ It can simplify or remove unnecessary work That’s how Rust keeps abstractions fast. 𝐁𝐮𝐭 𝐝𝐨𝐧’𝐭 𝐨𝐯𝐞𝐫𝐝𝐨 𝐢𝐭 Inlining copies code everywhere. Too much of it: ▪️ makes your program bigger ▪️ hurts CPU cache usage (very bad!) ▪️ can actually slow things down 𝐀 𝐬𝐦𝐚𝐫𝐭𝐞𝐫 𝐚𝐩𝐩𝐫𝐨𝐚𝐜𝐡 Instead of inlining everything: ▪️ Inline small, important functions (hot path) ▪️ Keep bigger, less-used logic separate (cold path) This keeps performance high and avoids bloating your code. In other words, if the code is not part of a critical path, don't inline it! Inlining is powerful—but only when used carefully. Have you ever had issues with inlining? Share them below 👇 Source: Check Brian Pane's Seattle Rust talk to see a 𝐫𝐞𝐚𝐥 𝐮𝐬𝐞 𝐜𝐚𝐬𝐞 𝐬𝐜𝐞𝐧𝐚𝐫𝐢𝐨: https://lnkd.in/eA9iVwXC (19:00 to 22:00) Also check out: https://lnkd.in/et8zhp3E
To view or add a comment, sign in
-
-
Can AI agents build software that comes with a mathematical proof that it works? At Basis Research Institute, we set four agents to build a verified compiler. Compilers are large, complex pieces of engineering, deep in the software stack. Anthropic recently showed that agents can build one from scratch. We wanted to ask the next question: can they build one that is verified correct? A verified compiler is one that comes with a machine-checked proof that it is mathematically correct. Most software is checked by running it on examples and checking its behaviour matches expectations. A proof guarantees it works on every example, including the ones no one ran. We tasked a team of agents to build a verified JS-to-WASM compiler in Lean. Over 14 days they wrote 93,000 lines of code and produced a compiler that ran. But they did not prove it correct. The agents built an interpreter, a target semantics, and the compiler between them. But the proofs never closed. They repeated broken strategies across sessions, forgot what had failed, and wrote the same lemma 122 times rather than abstracting it once. More capable models will help, but we think the bigger lever is verified program synthesis infrastructure designed around agents' capabilities and flaws. Full writeup: https://lnkd.in/er6mg4D4
To view or add a comment, sign in
-
Subject: Foundational Concept: DuCx Gedae, EXAMPLE The following is a simple example that illustrates the concept. The application entered in DuCx programming language: Z[i] ADconverter(int N) { range i = N; stream float z[i] = xxx; // declare data, read N floats data from hardware device } void exampleFunction() { int N = 16; range i = N; float A = 2.1, B = 0.4, C = 1.1; float x[i] = ADconverter(N); // N values in vector are input y[i] = A*x[i]^2 + B*x[i] + C; v_printf(“The answer is %f \n”,y); // output N values } The “^” is the power operator. The compiler generates an internal software model of the DuCx software. This model is accessible for the developer’s analysis of the structure, data and execution of the application. The sensor input function vf_ADconverter is autogenerated. The AD converter reads the input at a defined rate. The data is placed in a memory buffer and sets a flag to indicate that data is available. It is a stream function meaning that each time it executes it outputs a new value. All the inputs and outputs to the functions are digital data items. Their duration of existence in the operational system is determined by the structure of the DuCx code. This example illustrates parallelism of function execution. The compiler inserts a shared memory buffer to hold the values transferred from processor 1 to 2. Note: some hardware requires data to be transferred over a bus with send and receive functions. The compiler also adds code to control the execution. The buffer holds multiple data items to allow for parallel execution of the functions. An alternative parallelization strategy is to decompose the vectors into sub vectors and process them in parallel. The compiler generates the computer code in a standard language, e.g. C. The compiler has a definition of the target architecture, and the functions are mapped to that architecture. In this case the architecture has 2 processors and so there are 2 tasks running. The code generated by the compiler follows: void processor1(void) { int N = 16; float *x = vf_ADconverter(N); // vf_ADconverter is autogenerated from DuCx code float out1[N]; float A = 2.1; for(int i=0; i<N; i++) out1[i] = A*x1[i] * x1[i]; vf_send(out1,processor2 ); vf_send(x,processor2); } void processor2(void) { int N = 16; float out[N]; float B = 0.4; // could be an input from a user interface float C = 1.1; float *input1 = vf_receive (processor1,”out1”); float *x = vf_receive (processor1,”x”); for(int i=0; i<N; i++) out[i] = input1[i] + B*x[i] + C; vf_printf(“The output is %f\n”, out,N); } A launch package is generated that starts the 2 tasks on the processors. The m ethod is included in the definition of the hardware architecture. Since sf_ADconverter() is a stream function, the function processor1 is called multiple times and each time inputs and computes the vector of data and informs processor 2 that the data has been transferred.
To view or add a comment, sign in
-
𝗗𝗮𝘆 𝟵𝟰 𝗼𝗳 ∞: 𝗖𝗼𝗺𝗽𝗶𝗹𝗲𝗿 𝗕𝗹𝗮𝗰𝗸 𝗠𝗮𝗴𝗶𝗰 — -𝗢𝟯, -𝗺𝗮𝗿𝗰𝗵=𝗻𝗮𝘁𝗶𝘃𝗲, 𝗮𝗻𝗱 𝗣𝗚𝗢 🪄 Most developers write their C++ code, hit "Build," and assume the compiler is doing its best. In High-Frequency Trading, 𝗤𝘂𝗮𝗻𝘁𝘀 𝗱𝗼𝗻'𝘁 𝘁𝗿𝘂𝘀𝘁 𝘁𝗵𝗲 𝗱𝗲𝗳𝗮𝘂𝗹𝘁𝘀. 𝘛𝘩𝘦𝘺 𝘵𝘳𝘦𝘢𝘵 𝘵𝘩𝘦 𝘤𝘰𝘮𝘱𝘪𝘭𝘦𝘳 (𝘎𝘊𝘊 𝘰𝘳 𝘊𝘭𝘢𝘯𝘨) 𝘭𝘪𝘬𝘦 𝘢 𝘸𝘦𝘢𝘱𝘰𝘯. By passing the exact right flags, you can force the compiler to rewrite your logic, unlock hidden silicon, and predict the future. 𝘏𝘦𝘳𝘦 𝘢𝘳𝘦 𝘵𝘩𝘦 𝘵𝘩𝘳𝘦𝘦 𝘭𝘦𝘷𝘦𝘭𝘴 𝘰𝘧 𝘤𝘰𝘮𝘱𝘪𝘭𝘦𝘳 𝘰𝘱𝘵𝘪𝘮𝘪𝘻𝘢𝘵𝘪𝘰𝘯: 🔨 𝗟𝗲𝘃𝗲𝗹 𝟭: 𝗧𝗵𝗲 𝗦𝗹𝗲𝗱𝗴𝗲𝗵𝗮𝗺𝗺𝗲𝗿 (-𝗢𝟯) By default, compilers prioritize fast build times and easy debugging. That produces slow executables. By compiling with the -O3 flag, you tell the compiler to aggressively optimize for raw speed. 𝘐𝘵 𝘸𝘪𝘭𝘭 𝘢𝘶𝘵𝘰𝘮𝘢𝘵𝘪𝘤𝘢𝘭𝘭𝘺 "𝘪𝘯𝘭𝘪𝘯𝘦" 𝘺𝘰𝘶𝘳 𝘧𝘶𝘯𝘤𝘵𝘪𝘰𝘯𝘴 (𝘥𝘦𝘴𝘵𝘳𝘰𝘺𝘪𝘯𝘨 𝘵𝘩𝘦 𝘧𝘶𝘯𝘤𝘵𝘪𝘰𝘯 𝘤𝘢𝘭𝘭 𝘰𝘷𝘦𝘳𝘩𝘦𝘢𝘥) 𝘢𝘯𝘥 "𝘶𝘯𝘳𝘰𝘭𝘭" 𝘺𝘰𝘶𝘳 𝘧𝘰𝘳 𝘭𝘰𝘰𝘱𝘴 𝘵𝘰 𝘬𝘦𝘦𝘱 𝘵𝘩𝘦 𝘊𝘗𝘜 𝘱𝘪𝘱𝘦𝘭𝘪𝘯𝘦 𝘴𝘢𝘵𝘶𝘳𝘢𝘵𝘦𝘥. 🎯 𝗟𝗲𝘃𝗲𝗹 𝟮: 𝗧𝗵𝗲 𝗦𝗻𝗶𝗽𝗲𝗿 (-𝗺𝗮𝗿𝗰𝗵=𝗻𝗮𝘁𝗶𝘃𝗲) Even with -O3, the compiler generates "generic" assembly code so your program can run on any machine. But modern CPUs have incredibly powerful, specialized hardware instructions (like AVX-512 for SIMD math). By passing -march=native, you tell the compiler: "𝘍𝘰𝘳𝘨𝘦𝘵 𝘤𝘰𝘮𝘱𝘢𝘵𝘪𝘣𝘪𝘭𝘪𝘵𝘺. 𝘓𝘰𝘰𝘬 𝘢𝘵 𝘵𝘩𝘦 𝘦𝘹𝘢𝘤𝘵 𝘱𝘩𝘺𝘴𝘪𝘤𝘢𝘭 𝘊𝘗𝘜 𝘴𝘪𝘭𝘪𝘤𝘰𝘯 𝘐 𝘢𝘮 𝘴𝘵𝘢𝘯𝘥𝘪𝘯𝘨 𝘰𝘯, 𝘢𝘯𝘥 𝘦𝘹𝘱𝘭𝘰𝘪𝘵 𝘦𝘷𝘦𝘳𝘺 𝘴𝘪𝘯𝘨𝘭𝘦 𝘩𝘪𝘥𝘥𝘦𝘯 𝘪𝘯𝘴𝘵𝘳𝘶𝘤𝘵𝘪𝘰𝘯 𝘪𝘵 𝘩𝘢𝘴." 🔮 𝗟𝗲𝘃𝗲𝗹 𝟯: 𝗧𝗵𝗲 𝗛𝗼𝗹𝘆 𝗚𝗿𝗮𝗶𝗹 (𝗣𝗚𝗢) Normally, compilers have to guess. If you write an if/else statement, the compiler assumes it's a 50/50 coin toss and structures the assembly code neutrally. To beat this, 𝗛𝗙𝗧 𝗳𝗶𝗿𝗺𝘀 𝘂𝘀𝗲 𝗣𝗿𝗼𝗳𝗶𝗹𝗲-𝗚𝘂𝗶𝗱𝗲𝗱 𝗢𝗽𝘁𝗶𝗺𝗶𝘇𝗮𝘁𝗶𝗼𝗻 (𝗣𝗚𝗢). It is a 3-step process: 1. Compile the engine with a tracking flag. 2. Run the engine on a massive historical backtest. The engine records exactly which if branches were actually taken in the real world. 3. Re-compile the engine, feeding that tracking data back into the compiler. 𝘛𝘩𝘦 𝘤𝘰𝘮𝘱𝘪𝘭𝘦𝘳 𝘳𝘦𝘢𝘥𝘴 𝘵𝘩𝘦 𝘥𝘢𝘵𝘢, 𝘳𝘦𝘢𝘭𝘪𝘻𝘦𝘴 𝘵𝘩𝘦 𝘦𝘭𝘴𝘦 𝘣𝘭𝘰𝘤𝘬 𝘩𝘢𝘱𝘱𝘦𝘯𝘴 99.9% 𝘰𝘧 𝘵𝘩𝘦 𝘵𝘪𝘮𝘦, 𝘢𝘯𝘥 𝘱𝘩𝘺𝘴𝘪𝘤𝘢𝘭𝘭𝘺 𝘳𝘦𝘸𝘳𝘪𝘵𝘦𝘴 𝘵𝘩𝘦 𝘢𝘴𝘴𝘦𝘮𝘣𝘭𝘺 𝘤𝘰𝘥𝘦 𝘵𝘰 𝘱𝘳𝘪𝘰𝘳𝘪𝘵𝘪𝘻𝘦 𝘵𝘩𝘢𝘵 𝘦𝘹𝘢𝘤𝘵 𝘱𝘢𝘵𝘩. 𝗧𝗮𝗸𝗲𝗮𝘄𝗮𝘆: You can spend weeks optimizing your C++ source code, but 𝘪𝘧 𝘺𝘰𝘶 𝘥𝘰𝘯'𝘵 𝘰𝘱𝘵𝘪𝘮𝘪𝘻𝘦 𝘩𝘰𝘸 𝘪𝘵 𝘨𝘦𝘵𝘴 𝘵𝘳𝘢𝘯𝘴𝘭𝘢𝘵𝘦𝘥 𝘪𝘯𝘵𝘰 𝘮𝘢𝘤𝘩𝘪𝘯𝘦 𝘤𝘰𝘥𝘦, 𝘺𝘰𝘶 𝘢𝘳𝘦 𝘭𝘦𝘢𝘷𝘪𝘯𝘨 𝘧𝘳𝘦𝘦 𝘭𝘢𝘵𝘦𝘯𝘤𝘺 𝘰𝘯 𝘵𝘩𝘦 𝘵𝘢𝘣𝘭𝘦. #CPlusPlus #Quant #SoftwareEngineering #Compilers #Optimization #HighFrequencyTrading #ComputerScience #LearnCpp #Day94 #LearningJourney
To view or add a comment, sign in
-
-
[Backstage OCaml] Wasm_of_ocaml: What Changed Since 6.1: Wasm_of_ocaml compiles OCaml bytecode to WebAssembly, targeting WasmGC so that OCaml values are managed by the host garbage collector. This post covers the most relevant Wasm changes in versions 6.1 through 6.3, and three PRs that add WASI support, native effects via Stack Switching, and dynlink/toplevel support. The Background section at the end has a short recap of where the project fits alongside js_of_ocaml. What changed in 6.1-6.3 The full changelog covers all three releases in detail. Below are the changes most relevant to the Wasm backend. The compiler writes Wasm binaries directly now (6.1) Before 6.1, the compiler emitted WAT (WebAssembly text format) and then converted it to binary via Binaryen. Since 6.1, it writes .wasm binary modules directly, removing that conversion step. Binaryen is still a required system dependency. WAT output is still available for debugging and is also faster to generate now. Better Wasm code generation (6.1-6.3) Several changes across 6.1-6.3 improve the quality of the generated Wasm code: * Direct calls for known functions (6.1). When the compiler can determine the target of a function call at compile time, it emits a call_ref instruction. Having context on which functions are called where enables the Binaryen toolchain to better optimize the generated Wasm code. * Precise closure environment types (6.1). Closures carry refined WasmGC struct types for their captured variables instead of generic arrays. This gives the Wasm engine exact layout information. * Closure code pointer omission (6.2). When a closure is never called indirectly through a generic apply, the code pointer field is omitted from the closure struct entirely. * Number unboxing (6.3). The compiler tracks unboxed int/float values through chains of arithmetic operations and keeps them in Wasm locals instead of allocating heap boxes. This is the kind of optimization that makes tight numerical loops actually fast. * Reference unboxing (6.3). ref cells that don't escape a function become Wasm locals instead of heap-allocated mutable GC structs. * Specialized comparisons and bigarray ops (6.3). Instead of dispatching through caml_compare or generic bigarray accessors, the compiler emits type-specific Wasm instructions when it can resolve types statically. There are also shared compiler improvements (benefiting both js_of_ocaml and wasm_of_ocaml): the inlining pass was rewritten in 6.1 (#1935, #2018, #2027) with better tailcall optimization, deadcode elimination, and arity propagation between compilation units. Runtime additions (6.1-6.3) * Marshal now handles zstd-compressed values in the Wasm runtime (6.1, fix in 6.3). * Bigarray element access uses DataView get/set, which is faster than the typed array primitives that we used before (6.1). * Effect handler continuation resumption is more…
To view or add a comment, sign in
-
In .NET, the difference between an ArrayList and a List<T> is primarily about Type Safety and Performance. While both act as dynamically resizing arrays, ArrayList is a legacy collection from the early days of .NET, whereas List<T> is the modern, preferred standard. 1️⃣ ArrayList (The Legacy Container) Found in System.Collections, an ArrayList is a non-generic collection. It stores everything as a general object. Type Safety: None. You can add an integer, a string, and a custom object into the same ArrayList without the compiler complaining. This often leads to runtime crashes. Performance (Boxing/Unboxing): Because it stores everything as an object, value types (like int, double, bool) must be boxed (converted to a reference type) to be stored and unboxed to be retrieved. This is computationally expensive. Namespace: System.Collections. 2️⃣ List (The Modern Standard) Found in System.Collections.Generic, List<T> is a generic collection. You specify the type of data it will hold when you declare it (e.g., List<int>). Type Safety: High. If you declare a List<int>, the compiler will stop you if you try to add a string. This catches errors during development rather than at runtime. Performance: Significantly faster for value types. Because the list knows exactly what type it is holding, it avoids the overhead of boxing and unboxing. Namespace: System.Collections.Generic. 🛡️ Type Safety: ArrayList is like a box labeled "Stuff"—anything fits, which is a recipe for runtime crashes. List<int> is a box labeled "Integers Only"—the compiler acts as your bodyguard. ⚡ Performance: Every time you put an integer into an ArrayList, .NET has to perform "Boxing" (wrapping it in an object). When you take it out, it has to "Unbox" it. This wastes CPU cycles and memory. List<T> talks to the memory directly, making it lightning fast. 🛠️ Clean Code: With Generics, your code is more readable and easier to maintain. No more casting (int)myArrayList[0] every time you want to use a value. The Verdict: Unless you are maintaining a legacy application from 2002, always reach for System.Collections.Generic.List<T>. #dotnet #dotnetcore #aspnetcore #csharp #aspnet #microsoftdotnet #dotnetdeveloper #aspnetmvc #mvc #dotnetmvc #aspnetcoremvc
To view or add a comment, sign in
-
-
𝗗𝗮𝘆 𝟵𝟮 𝗼𝗳 ∞: 𝗛𝘂𝗻𝘁𝗶𝗻𝗴 𝗠𝗲𝗺𝗼𝗿𝘆 𝗕𝘂𝗴𝘀 𝗶𝗻 𝗖++ — 𝗩𝗮𝗹𝗴𝗿𝗶𝗻𝗱 𝘃𝘀. 𝗔𝗱𝗱𝗿𝗲𝘀𝘀𝗦𝗮𝗻𝗶𝘁𝗶𝘇𝗲𝗿 🐛 We just spent weeks making our C++ matching engine incredibly fast. But in High-Frequency Trading, raw speed is completely useless if your server segfaults and crashes at 2:00 PM during a market rally. Because C++ gives you direct access to the metal, memory leaks and buffer overflows are the silent killers of low-latency systems. Here is how modern engineers hunt them down. 🕵️♂️ 𝗧𝗵𝗲 𝗢𝗹𝗱 𝗚𝘂𝗮𝗿𝗱: 𝗩𝗮𝗹𝗴𝗿𝗶𝗻𝗱 For decades, the undisputed king of memory debugging was Valgrind (𝘀𝗽𝗲𝗰𝗶𝗳𝗶𝗰𝗮𝗹𝗹𝘆 𝘁𝗵𝗲 𝗠𝗲𝗺𝗰𝗵𝗲𝗰𝗸 𝘁𝗼𝗼𝗹 ). 𝘝𝘢𝘭𝘨𝘳𝘪𝘯𝘥 𝘢𝘤𝘵𝘴 𝘢𝘴 𝘢 𝘷𝘪𝘳𝘵𝘶𝘢𝘭 𝘮𝘢𝘤𝘩𝘪𝘯𝘦. It tracks every single memory allocation and every single byte read/written. If you leak memory or access a dangling pointer, Valgrind catches it. 𝗧𝗵𝗲 𝗱𝗼𝘄𝗻𝘀𝗶𝗱𝗲? 𝘐𝘵 𝘴𝘭𝘰𝘸𝘴 𝘺𝘰𝘶𝘳 𝘱𝘳𝘰𝘨𝘳𝘢𝘮 𝘥𝘰𝘸𝘯 𝘣𝘺 20𝘹 𝘵𝘰 50𝘹. It is fantastic for deep debugging sessions, but far too slow to run on massive, continuous integration (CI) test suites. 🛡️ 𝗧𝗵𝗲 𝗠𝗼𝗱𝗲𝗿𝗻 𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱: 𝗔𝗱𝗱𝗿𝗲𝘀𝘀𝗦𝗮𝗻𝗶𝘁𝗶𝘇𝗲𝗿 (𝗔𝗦𝗮𝗻) Today, the industry standard is 𝗔𝗱𝗱𝗿𝗲𝘀𝘀𝗦𝗮𝗻𝗶𝘁𝗶𝘇𝗲𝗿, a tool built directly into modern compilers like GCC and Clang (-fsanitize=address). Instead of running a virtual machine, ASan instruments your code at compile time. 𝗧𝗵𝗲 𝗠𝗮𝗴𝗶𝗰 𝗼𝗳 "𝗣𝗼𝗶𝘀𝗼𝗻𝗲𝗱 𝗥𝗲𝗱𝘇𝗼𝗻𝗲𝘀": 𝘞𝘩𝘦𝘯𝘦𝘷𝘦𝘳 𝘺𝘰𝘶 𝘢𝘭𝘭𝘰𝘤𝘢𝘵𝘦 𝘮𝘦𝘮𝘰𝘳𝘺 (𝘭𝘪𝘬𝘦 𝘢𝘯 𝘢𝘳𝘳𝘢𝘺 𝘰𝘧 5 𝘪𝘯𝘵𝘦𝘨𝘦𝘳𝘴), 𝘈𝘚𝘢𝘯 𝘴𝘦𝘤𝘳𝘦𝘵𝘭𝘺 𝘱𝘢𝘥𝘴 𝘵𝘩𝘦 𝘦𝘥𝘨𝘦𝘴 𝘰𝘧 𝘵𝘩𝘢𝘵 𝘮𝘦𝘮𝘰𝘳𝘺 𝘸𝘪𝘵𝘩 "𝘱𝘰𝘪𝘴𝘰𝘯𝘦𝘥" 𝘣𝘺𝘵𝘦𝘴. If you accidentally write a loop that tries to access the 6th element, your pointer hits the poison. ASan instantly halts the program and prints a beautiful stack trace telling you the exact line number where the heap-buffer-overflow occurred. Because it is baked into the compiler, ASan only slows your code down by about 2x. This means HFT firms can run their entire suite of automated backtests with ASan enabled, mathematically guaranteeing memory safety before a single line of code hits the exchange. 𝗧𝗮𝗸𝗲𝗮𝘄𝗮𝘆: 𝘎𝘳𝘦𝘢𝘵 𝘊++ 𝘥𝘦𝘷𝘦𝘭𝘰𝘱𝘦𝘳𝘴 𝘥𝘰𝘯'𝘵 𝘨𝘶𝘦𝘴𝘴 𝘪𝘧 𝘵𝘩𝘦𝘪𝘳 𝘮𝘦𝘮𝘰𝘳𝘺 𝘪𝘴 𝘴𝘢𝘧𝘦. 𝘛𝘩𝘦𝘺 𝘦𝘯𝘧𝘰𝘳𝘤𝘦 𝘪𝘵 𝘢𝘵 𝘤𝘰𝘮𝘱𝘪𝘭𝘦 𝘵𝘪𝘮𝘦. #CPlusPlus #Quant #SoftwareEngineering #Debugging #Valgrind #AddressSanitizer #ComputerScience #LearnCpp #Day92 #LearningJourney
To view or add a comment, sign in
-
Explore related topics
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development