<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/programming-language-semantics-and-memory-safety-4irru6jgw" -->

---
title: Programming Language Semantics and Memory Safety | daily.dev
description: An exploration of formal programming language semantics—operational, denotational, and axiomatic—explained through a toy language, then connected to memory...
canonical: https://daily.dev/posts/programming-language-semantics-and-memory-safety-4irru6jgw
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Programming Language Semantics and Memory Safety | daily.dev
og:description: An exploration of formal programming language semantics—operational, denotational, and axiomatic—explained through a toy language, then connected to memory...
og:url: https://daily.dev/posts/programming-language-semantics-and-memory-safety-4irru6jgw
og:image: https://api.daily.dev/og/posts/4irRu6jGw.png
og:image:alt: Programming Language Semantics and Memory Safety
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Programming Language Semantics and Memory Safety

**[Lobsters](https://daily.dev/sources/lobsters)** · 14 min read · 7 upvotes · 0 comments

## Summary

An exploration of formal programming language semantics—operational, denotational, and axiomatic—explained through a toy language, then connected to memory safety and undefined behavior in C/C++. The piece explains how compilers exploit axiomatic assumptions about UB to optimize code (e.g., removing bounds checks), why C's UB creates a 'logical void' that invalidates surrounding guarantees, and how Rust's borrow checker acts like a proof assistant to eliminate UB. Written by a former Rust-at-Google lead who also worked on Carbon language design.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://burakemir.ch/post/formal-semantics>

## Questions this post answers

### Why does a C compiler remove the bounds check in a loop like `for (int i = 0; i <= 10; i++) table[i] = 0;` when table has only 10 elements?

Because out-of-bounds array access is undefined behavior in the C standard, compilers like GCC and Clang can axiomatically assume it never happens. Since table[10] would be UB, the compiler infers i can never reach 10, meaning i <= 10 is always true, and optimizes the loop into an infinite loop with the bounds check removed entirely.

_For developers debugging surprising compiler optimizations around undefined behavior, daily.dev surfaces deeper explainers on C/C++ semantics and memory safety._

### What is the difference between operational semantics and axiomatic semantics for defining a programming language?

Operational semantics defines meaning by describing step-by-step how a program executes on an abstract machine, similar to how an interpreter works, while axiomatic semantics defines meaning through logical preconditions and postconditions using Hoare triples like {P} C {Q}, similar to assertions or unit tests. The ECMAScript spec for JavaScript uses operational semantics, while formal verification tools like Coq or Dafny rely on axiomatic semantics.

_Developers comparing language semantics approaches can find related programming language theory discussions on daily.dev._

### How does Rust's borrow checker relate to formal semantics and memory safety proofs?

Rust's borrow checker acts as a proof assistant that ensures, from the axioms and rules of memory safety, a program is allowed to compile only when those rules hold, such as reading only from initialized memory. This is described as a more rigorous approach than patching operational gaps in C, and unsafe Rust permits deviating from these rules only when a developer can argue in safety comments that the memory safety axioms still hold.

_Teams weighing Rust adoption for memory safety guarantees can track deeper technical breakdowns like this on daily.dev._

## Community take

How the wider developer community reacted, aggregated from 3 discussions and 13 comments across hackernews, lobsters (as of 2026-09-14).

**TL;DR:** The deep dive into axiomatic semantics and UB was praised by several readers as clarifying, but it also sparked a long technical debate about whether memory safety is a property of a language's semantics or of its implementation, with one commenter finding the piece underwhelming.

**Sentiment:** 45% positive · 45% mixed · 10% skeptical

**The case for**

- Several found the axiomatic-semantics framing of undefined behavior genuinely new and clarifying.
- One reader said it finally made clear the reasoning behind why UB is treated as both 'can do anything' and 'assumed not to happen'.
- One person praised it for reminding readers of the small-step/big-step/axiomatic distinction and connecting language-as-artifact to language-as-abstraction.

**The pushback**

- A recurring objection is that memory safety is arguably a property of an implementation, not of the language's abstract semantics.
- One commenter argued the examples and conclusions were poor and obvious, and didn't see what made the piece exceptional.
- A side debate questioned whether the piece's line equating 'safety' with 'cybersecurity' overgeneralizes, since safety concerns vary heavily by domain (e.g., firmware vs. word processors).

**By community**

- hackernews (mixed): No comments were available, so there's no discernible discussion to characterize.
- lobsters (mixed): Praise for the fresh axiomatic take on UB coexists with a substantive pushback on whether memory safety belongs to language semantics or implementation, plus one dissenting reader who found the article unremarkable.

**Hottest debate:** Whether memory safety is fundamentally a property of a language's abstract semantics or of its concrete implementation.

**Open questions**

- Can a programming language have nontrivial semantic properties independent of any implementation, or does all meaningful semantics reduce to implementation behavior?
- Is memory safety best understood as a hyperproperty spanning execution traces rather than just about undefined/'stuck' states?

**Highlights**

> Excellent post! The axiomatic view of UB was new to me! Though, [my usual quibble applies](https://matklad.github.io/2025/12/30/memory-safety-is.html): memory safety is a property of the implementation, and not of the language itself. Semantics getting “stuck” is not a problem per se,  the implementation _could_ safely halt in this case.
> — [matklad on lobsters · 6 points, 1 comments](https://lobste.rs/s/lmpkkr/programming_language_semantics_memory#c_vnpydl)

> Roughly speaking, a semantics describes the transitions (in an operational semantics) or reductions (in a denotational semantics) that are permitted, and you’d expect the permitted steps to describe something nontrivially useful. The question is what happens when there isn’t a step specified in the semantics: does the implementation detect the situation and stop with an error, or blunder on? Or did the compiler prove that this kind of situation can never occur? Back when I was learning this stuff in the 1990s, the typical aim when writing a formal semantics for a programming language was to demonstrate that a program could not get into a situation at run time where there were no valid steps (other than explicit cases like an uncaught exception). This was summarized by Robin Milner’s slogan, “[well-typed programs cannot go wrong](https://homepages.inf.ed.ac.uk/wadler/papers/papers-we-love/milner-type-polymorphism.pdf)”. Which of course uses an excessively technical meaning of “go wrong” and even now 48 years later programmers are still arguing at cross purposes over whether not going wrong means having defined semantics or not being buggy.
> — [fanf on lobsters · 3 points, 1 comments](https://lobste.rs/s/lmpkkr/programming_language_semantics_memory#c_6ng97v)

> Matklad mentions this at the end of his post, but there are some views of memory safety (e.g. [The meaning of memory safety](https://link.springer.com/content/pdf/10.1007/978-3-319-89722-6_4.pdf) or [The downgrading semantics of memory safety](https://arxiv.org/abs/2507.11282)) that define memory safety as a (proper) hyperproperty, i.e. a property that can not be refuted by a single execution trace (finite or infinite) of a program. From this point of view, memory safety is about more than what happens when there isn’t a permitted step in the semantics.
> — [zwarich on lobsters · 1 points, 1 comments](https://lobste.rs/s/lmpkkr/programming_language_semantics_memory#c_sxsjpa)

> I'm left scratching my head at what I missed in the article (which I read in its entirety) that qualified it as "great" and (matklad) "excellent". The examples seemed poor and obvious, and the conclusions seemed similarly poor and obvious. Maybe my expectations were just way too high? The only thing I learned was that he or she worked at Google, and I learned that several times over. The topic is one that I am interested in. This article didn't do it for me.
> — [cpurdy on lobsters · 1 points, 2 comments](https://lobste.rs/s/lmpkkr/programming_language_semantics_memory#c_cymgrj)

> I've never looked at UB from the perspective of axiomatic semantics, so this was a new tool of thought to me. And I think the article is great for general audience, because it's useful to remind people about small step, big step, and axiomatic (which is always forgotten) view, and, more generally, to remind that there's "programming language as engineering artifact" and "programming language as mathematical abstraction", and how the properties of the two are connected. "I personally learned something new" + general educational value is my bar for an excellent article! I do agree that the exposition could be a quite a bit more concrete, but I judge articles by what they make me think, not what's written in them :P
> — [matklad on lobsters · 2 points](https://lobste.rs/s/lmpkkr/programming_language_semantics_memory#c_kzvxds)

**Source threads**

- [hackernews](https://news.ycombinator.com/item?id=49389417) · 3 points · 0 comments
- [lobsters](https://lobste.rs/s/lmpkkr/programming_language_semantics_memory) · 14 points · 13 comments
- [hackernews](https://news.ycombinator.com/item?id=49396875) · 1 points · 0 comments

## Similar posts on daily.dev

- [Everything in C is undefined behavior](https://daily.dev/posts/everything-in-c-is-undefined-behavior-lf4o5xfht) · Hacker News · 21 upvotes · 1 comments
- [Memory safety is a matter of life and death](https://daily.dev/posts/memory-safety-is-a-matter-of-life-and-death-5zvkfxka2) · Lobsters · 11 upvotes · 1 comments
- [Beyond Memory Safety: What Makes Rust Different – Lessons from Autonomous Robotics](https://daily.dev/posts/beyond-memory-safety-what-makes-rust-different-lessons-from-autonomous-robotics-ivljxogzh) · InfoQ · 0 upvotes · 0 comments

---

Tags: [#rust](https://daily.dev/tags/rust), [#c](https://daily.dev/tags/c)

[View this post on daily.dev](https://daily.dev/posts/programming-language-semantics-and-memory-safety-4irru6jgw)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Programming Language Semantics and Memory Safety","url":"https://daily.dev/posts/programming-language-semantics-and-memory-safety-4irru6jgw","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/programming-language-semantics-and-memory-safety-4irru6jgw"},"datePublished":"2026-08-22T22:34:13.380Z","dateModified":"2026-09-14T07:42:59.208Z","description":"An exploration of formal programming language semantics—operational, denotational, and axiomatic—explained through a toy language, then connected to memory...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/76c31ffd2ad338b74ee29fa7db8adfa2?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/76c31ffd2ad338b74ee29fa7db8adfa2?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Lobsters","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Lobsters","logo":"https://media.daily.dev/image/upload/s--tl8v_Fku--/f_auto,t_logo/v1698841318/logos/lobste.jpg","url":"https://daily.dev/sources/lobsters"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/programming-language-semantics-and-memory-safety-4irru6jgw","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":7},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"rust,c","timeRequired":"PT14M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Lobsters","item":"https://daily.dev/sources/lobsters"},{"@type":"ListItem","position":3,"name":"Programming Language Semantics and Memory Safety"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/programming-language-semantics-and-memory-safety-4irru6jgw#faq","mainEntity":[{"@type":"Question","name":"Why does a C compiler remove the bounds check in a loop like `for (int i = 0; i <= 10; i++) table[i] = 0;` when table has only 10 elements?","acceptedAnswer":{"@type":"Answer","text":"Because out-of-bounds array access is undefined behavior in the C standard, compilers like GCC and Clang can axiomatically assume it never happens. Since table[10] would be UB, the compiler infers i can never reach 10, meaning i <= 10 is always true, and optimizes the loop into an infinite loop with the bounds check removed entirely. For developers debugging surprising compiler optimizations around undefined behavior, daily.dev surfaces deeper explainers on C/C++ semantics and memory safety."}},{"@type":"Question","name":"What is the difference between operational semantics and axiomatic semantics for defining a programming language?","acceptedAnswer":{"@type":"Answer","text":"Operational semantics defines meaning by describing step-by-step how a program executes on an abstract machine, similar to how an interpreter works, while axiomatic semantics defines meaning through logical preconditions and postconditions using Hoare triples like {P} C {Q}, similar to assertions or unit tests. The ECMAScript spec for JavaScript uses operational semantics, while formal verification tools like Coq or Dafny rely on axiomatic semantics. Developers comparing language semantics approaches can find related programming language theory discussions on daily.dev."}},{"@type":"Question","name":"How does Rust's borrow checker relate to formal semantics and memory safety proofs?","acceptedAnswer":{"@type":"Answer","text":"Rust's borrow checker acts as a proof assistant that ensures, from the axioms and rules of memory safety, a program is allowed to compile only when those rules hold, such as reading only from initialized memory. This is described as a more rigorous approach than patching operational gaps in C, and unsafe Rust permits deviating from these rules only when a developer can argue in safety comments that the memory safety axioms still hold. Teams weighing Rust adoption for memory safety guarantees can track deeper technical breakdowns like this on daily.dev."}}]}
```

