Mert Özen Further With Every Line

Blog

Mert Özen's blog posts on software development, backend, frontend, and DevOps.

Series
8 posts found
How Code Becomes Runnable: A Map of Compilers, Interpreters, JIT and AOT
Computer Science Fundamentals PART 01

How Code Becomes Runnable: A Map of Compilers, Interpreters, JIT and AOT

There is no such thing as a compiled or an interpreted language; which stages run at build time and which at run time is the implementation's choice. A C# method called 1,500 times is compiled by the JIT only three times, TypeScript types are checked at build time and erased, and V8 first interprets code and then compiles it with Maglev and TurboFan. The post shows the compiler pipeline with real output and drafts the grammar of the Bookstore filter language we build in this series.

15 Nov 2026 14 min 4
Writing a Lexer: From Characters to Tokens with a Bookstore Filter Language in C#
Computer Science Fundamentals PART 02

Writing a Lexer: From Characters to Tokens with a Bookstore Filter Language in C#

A lexer is a state machine that splits characters into tokens and knows the line and column of each one. We write a single-pass C# lexer over ReadOnlySpan<char> for the Bookstore filter language: maximal munch, keyword matching that survives the Turkish culture, number parsing with InvariantCulture, error recovery that respects surrogate pairs, and clear error messages. Real output shows where a regex lexer breaks and why Roslyn keeps whitespace as trivia.

15 Nov 2026 14 min 6
Parsers and ASTs: Recursive Descent, Operator Precedence and Pratt Parsing
Computer Science Fundamentals PART 03

Parsers and ASTs: Recursive Descent, Operator Precedence and Pratt Parsing

A parser turns tokens into a single AST following precedence and associativity rules; Pratt parsing keeps those rules in a binding power table instead of a chain of methods. For the Bookstore filter language we derive a recursive descent parser from the grammar, write the same language with a Pratt parser and test that both build the same tree, report several errors at once with panic mode, and run the AST with a tree-walking interpreter.

15 Nov 2026 15 min 9
Semantic Analysis and Code Generation: Type Checking, Symbol Tables and Compiling an AST to Expression Trees
Computer Science Fundamentals PART 04

Semantic Analysis and Code Generation: Type Checking, Symbol Tables and Compiling an AST to Expression Trees

Semantic analysis binds the names in a parsed tree to a symbol table and checks types, so a mistake like price = "abc" is caught before the filter touches any book. For the Bookstore filter language we write a binder with implicit conversion and constant folding, compile the verified tree to Expression<Func<Book,bool>>, run it in memory and use ToQueryString to show EF Core turning it into parameterized SQL; we also see why an input length limit is needed and what Roslyn does.

15 Nov 2026 16 min 8
IL and the JIT Compiler: Tiered Compilation, Dynamic PGO, Inlining and Escape Analysis
Computer Science Fundamentals PART 05

IL and the JIT Compiler: Tiered Compilation, Dynamic PGO, Inlining and Escape Analysis

The JIT does not compile a method once but in tiers: first unoptimized Tier0, then an instrumented copy, finally a Tier1 optimized with the collected profile. With Bookstore code and DOTNET_JitDisasm output we show IL's stack-based form, OSR, Dynamic PGO turning an interface call into direct code behind a type check, bounds check elimination and .NET 10's escape analysis taking a 40-byte allocation down to zero, and compare it with V8's hidden classes and deoptimization.

15 Nov 2026 19 min 8
AOT Compilation: ReadyToRun, Native AOT and the Startup vs Throughput Trade-off
Computer Science Fundamentals PART 06

AOT Compilation: ReadyToRun, Native AOT and the Startup vs Throughput Trade-off

Native AOT produces machine code at publish time and clearly reduces startup time and memory; the price is trimming, no dynamic code, platform-specific builds and no Dynamic PGO. We publish the same Bookstore API with JIT, ReadyToRun and Native AOT and measure startup, memory and throughput, and show the warnings our filter language hits, a trimming bug that returns 500 without any warning, and the cost of Expression.Compile() falling back to an interpreter.

15 Nov 2026 13 min 10
How Garbage Collection Works: Mark-Sweep-Compact, Generational GC and .NET Server GC
Computer Science Fundamentals PART 07

How Garbage Collection Works: Mark-Sweep-Compact, Generational GC and .NET Server GC

A tracing GC marks the objects reachable from the roots and treats the rest as garbage; .NET splits this work into generations and keeps gen0 GCs cheap with a write barrier and a card table. With dotnet-counters and BenchmarkDotNet we show the Bookstore filter language's interpreter producing 10 GB of allocations and 1,365 gen0 GCs in five seconds while the compiled delegate triggers none, and measure the LOH, Workstation and Server GC, DATAS, and a real leak versus uncollected memory.

15 Nov 2026 14 min 10
How Programming Languages Evolve: Paradigms from Lisp to C# and the Road to Runtime Async
Computer Science Fundamentals PART 08

How Programming Languages Evolve: Paradigms from Lisp to C# and the Road to Runtime Async

Language features are often born as a trick the compiler imitates with existing constructs, and once they spread the runtime supports them directly: generics, lambdas and .NET 11's Runtime Async are examples. A short family tree from Fortran and Lisp to C#, paradigms used together in C#, static/dynamic and strong/weak typing, the nominal versus structural difference between C# and TypeScript, and a live stack that drops from 13 lines to 5 with Runtime Async, all with real output.

15 Nov 2026 11 min 8
Blog Map