Mert Özen Further With Every Line

Blog

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

Series
74 posts found
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 9
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
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
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 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 9
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
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 7
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 5
Concurrency Models and Verifying Concurrent Code: Shared Memory, Actors, CSP and Model Checking
Computer Science Fundamentals PART 08

Concurrency Models and Verifying Concurrent Code: Shared Memory, Actors, CSP and Model Checking

A concurrency model decides who owns the state and how parts communicate: with shared memory everyone takes turns through a lock, with actors and CSP the state has a single owner and communication is by message. We build Bookstore's stock reservation with a lock, an actor and a channel pipeline, show a read-then-write protocol selling 4,000 books from 1,000 in stock while the actor itself is bug-free, and model check the same check-then-act bug in TLA+ and read TLC's counterexample.

14 Nov 2026 13 min 15
Lock-Free and Wait-Free: CAS Loops, the ABA Problem and Linearizability
Computer Science Fundamentals PART 07

Lock-Free and Wait-Free: CAS Loops, the ABA Problem and Linearizability

A lock-free algorithm guarantees that at least one thread makes progress even under contention, a wait-free one that every thread does. We write a counter and a Treiber stack with CAS loops, and measure on ARM64 that pooling nodes brings back the ABA problem and loses hundreds of thousands of 8 million ids, that a small checker finds non-linearizable histories in a broken stack, and that the CAS loop is 16 times slower than a lock on 8 threads.

14 Nov 2026 13 min 15
The .NET Memory Model: Happens-Before, Acquire/Release, volatile and Safe Object Publication
Computer Science Fundamentals PART 06

The .NET Memory Model: Happens-Before, Acquire/Release, volatile and Safe Object Publication

In the .NET memory model ordinary accesses may be reordered; Volatile.Read is an acquire, Volatile.Write a release, and Interlocked and lock are the points that guarantee order. We show a non-volatile stop flag loop never stopping in a Release build because of the JIT, double-checked locking with a bool flag returning null 36 times in 20 million calls on ARM64, derive from the spec why checking the reference is correct, and compare with Java, C++ and Go.

14 Nov 2026 11 min 15
Hardware Memory Models: Reordering, Store Buffers, Cache Coherence and Sequential Consistency
Computer Science Fundamentals PART 05

Hardware Memory Models: Reordering, Store Buffers, Cache Coherence and Sequential Consistency

Modern CPUs do not give sequential consistency: the store buffer lets a read overtake an earlier write, and ARM64 reorders even more. On ARM64 we measure both threads reading 0 in 5.3 million of 10 million rounds of the classic store buffering test and a flag becoming visible before the data in the message passing test, explain why cache coherence does not prevent this, and show from Intel's manual which outcomes x64 forbids.

14 Nov 2026 12 min 15
Blog Map