From: Ralf Jung Date: Thu, 24 Jul 2025 16:24:03 +0000 (+0200) Subject: java-safe wording X-Git-Url: https://git.ralfj.de/web.git/commitdiff_plain/f97f7a70b9ff9851a1ea4b22581e565a5b2b06a7?hp=3e019d0e5ed525050b953b4c881631d3984e99ae java-safe wording --- diff --git a/personal/_posts/2025-07-24-memory-safety.md b/personal/_posts/2025-07-24-memory-safety.md index 45bdc32..26a2427 100644 --- a/personal/_posts/2025-07-24-memory-safety.md +++ b/personal/_posts/2025-07-24-memory-safety.md @@ -89,7 +89,7 @@ They even developed the [first industrially deployed concurrency memory model](h The result of all of this work is that in a concurrent Java program, you might see unexpected outdated values for certain variables, such as a null pointer where you expected the reference to be properly initialized, but you will *never* be able to actually break the language and dereference an invalid dangling pointer and segfault at address `0x2a`. In that sense, all Java programs are thread-safe.[^java-safe] -[^java-safe]: Java programmers will sometimes use the terms "thread safe" and "memory safe" differently than C++ or Rust programmers would. From a Rust perspective, Java programs are memory- and thread-safe by construction. Java programmers take that so much for granted that they use the same term to refer to stronger properties, such as absence of null pointer exception or absence of unintended data races. However, Java null pointer exceptions and data races cannot cause segfaults from invalid pointer uses, so these kinds of issues are qualitatively very different from the memory safety violation in my Go example. For the purpose of this blog post, I am using the low-level Rust and C++ meaning of these terms. +[^java-safe]: Java programmers will sometimes use the terms "thread safe" and "memory safe" differently than C++ or Rust programmers would. From a Rust perspective, Java programs are memory- and thread-safe by construction. Java programmers take that so much for granted that they use the same term to refer to stronger properties, such as not having "unintended" data races or not having null pointer exceptions. However, such bugs cannot cause segfaults from invalid pointer uses, so these kinds of issues are qualitatively very different from the memory safety violation in my Go example. For the purpose of this blog post, I am using the low-level Rust and C++ meaning of these terms. Generally, there are two options a language can pursue to ensure that concurrency does not break basic invariants: - Ensure that arbitrary concurrent programs actually behave "reasonably" in some sense. This comes at a significant cost, restricting the language to never assume consistency of multi-word values and limiting which optimizations the compiler can perform. This is the route most languages take, from Java to C#, OCaml, JavaScript, and WebAssembly.