Joint SRUG+NWCPP
2025.07 Meetup

Upcoming C++/Rust Meetups

  • THIS is our Final Meetup at the MSFT Reactor
     
  • In search of a new home for Aug 21 (3rd Thu)
     

After-Meet Gathering

All are invited to gather tonight at
Red Robin

Joint Gathering!

Language Panel Presentation

Panel Introductions

Donna Smith
Cpp2

Theodore "Ted" Neward
C#, Mojo

Walter Bright
D

Dread Pirate Williamson
Swift

Lloyd Moore
C++

Brad Gibson
Rust

Donna Smith
Cpp2

Dread Pirate Williamson
Swift

Theodore "Ted" Neward
C#

Theodore "Ted" Neward
Mojo

Walter Bright
D

Language History

Who: Created by Walter Bright

What: The D Programming Language

Where: In my office

When: Started in 1999, release 1.0 in 2007

Why: Having developed a C and standard compliant C++ compiler, there was a
        large opportunity to learn from those languages and create a much
        better language.

How: Initially implemented using a "C with Classes" style code, then converted
        the entire implementation in D. The community appeared and greatly
        expanded the D ecosystem.

Status: Mature production compilers DMD, gnu based GDC, and LLVM based
        LDC Update

Schedule: Generally when we feel there's enough to justify a new release Standards Body: The D Language Foundation

Sample Code

// Courtesy of Bruce Carneal
import core.atomic : atomicOp, atomicLoad;
import std.parallelism : parallel;
import std.range : iota;
import std.stdio : writeln;

enum threadCount = 100;
enum incrementsPerThread = 10000;
enum expected = threadCount * incrementsPerThread;

void main() {
    shared(ulong)* counter = new ulong;

    // Forces 100 threads by limiting the number of work items per thread to '1'
    foreach (i; parallel(iota(0, threadCount), 1)) {
        foreach (_; 0 .. incrementsPerThread)
            atomicOp!"+="(*counter, 1);
    }

    writeln("Expected total count: ", expected, "; Actual count: ", atomicLoad(*counter));
}

Memory Safety Features

Memory / Lifetime Management: pure functions, @safe code, optional Garbage
        Collection, scoped pointers, RAII, contracts, member access protection Automatic Bounds Checking: Yes

Safe Arithmetic: No, Yes with library functions

Pointers and References: Both

References are safer Forced Initialization: Yes, but can turn off in @system
        code

Pointer Arithmetic: Yes, but only in @system code

Managed Ownership: Garbage Collection, ref counting library type

Thread Safety Features

Sync Primitives: Atomics, Locks, Memory Barriers
Reentrant Safety: Yes if you use only local data and avoid shared mutable state Thread Local Storage: Yes (by default)
Immutable Objects: Yes, and const/immutability is transitive
Immutable by Default: No
Communication Primitives: Library

Performance

Translation: Compiled, matches C/C++ performance
Deterministic @ Runtime: Yes
Bare Metal Programming: Yes (includes inline assembler!)
Other Features: Excellent meta programming enabling easy refactoring for
        more efficient algorithms, compile time function evaluation, bitfields, array
        operations, SIMD code generation

Development Ecosystem

Available Tool Chains: Digital Mars D, Gnu D, and LDC

D Library Support: Some, C libraries are accessible via ImportC

Package Managers: DUB IDE / Editor

Support: Many, including dedicated IDEs like Dexed and D-Veldop, as well as plugins for popular editors like IntelliJ IDEA, Visual Studio Code, and more. Language Server Available: Yes - serve-d
Community: Medium

Other Considerations

Easy or hard to learn? Remarkably easy to learn, code is easy to read
Easy or hard to find developers? C and C++ programmers fit right in, Python
        programmers report it's an easy transition to D
Suitable for use in regulated environments? Yes
Suitable for use in embedded environments? Yes
Job Availability by career level: at all levels
Special features: Best metaprogramming, easiest compile time function
        execution, can import C code directly, excellent module system, pure
        functions, lambdas, ranges, forward referencing, nested functions, static
        asserts (copied by other languages!)

Lloyd Moore
C++

Brad Gibson
Rust

Rust

What is It?

 

Rust is a compiled, non-garbage-collected, multi-paradigm
systems programming language designed to to operate in the same spaces as both C and C++.

Rust

Who Created It?

 

Rust was created by a language engineer named
Graydon Hoare.

Rust

Where Was Rust Created?

 

Graydon worked at Mozilla when he started developing Rust as a personal project.

Rust

When was Rust Created?

 

Graydon started to work on Rust in 2006.

Rust 1.0 was released May 15, 2015.

Rust

Language Goals:

  • Reliability
    • "Rust’s rich type system and ownership model guarantee memory-safety and thread-safety — enabling you to eliminate many classes of bugs at compile-time."
  • Performance
    • C and C++ class performance
  • Productivity
    • Very good documentation
    • Friendly compiler (usually), if strict

Why Was Rust Created?

Rust

How Was Rust Created?

 

  • Rust bootstrapping α-compiler released in 2010 (OCaml).
  • Rust becomes self-hosting in early 2011.
  • Rust 1.0 (production, stability guarantees) was released May 15, 2015 (Rust).

 

Graydon cites inspiration from Ada, OCaml, CLU and Hermes.


Wikipedia also lists Alef, BETA, C#, C++, Cyclone, Elm, Erlang, Haskell, Limbo, Mesa, Napier, Newsqueak, NIL, Ruby, Sather, Scheme, Standard ML and Swift as influences.

Rust

Release Schedule

 

  • Release Cadence: every 6 weeks
  • Edition cadence: every 3 years
    • Editions permit (limited) breaking language changes
      with both backward and forward compatibility (!)

Rust

Status

 

  • Latest release: 1.88.0 (June 26, 2025)
  • Safety-critical Rust (Ferrocene) is currently qualified as:
    • ISO 26262 & ASIL-D (automotive)
    • IEC 61508 (SIL 4) (industrial manufacturing)
    • IEC 62304 (Class C) (medical development)
  • GCC back-end support under development (currently LLVM)
  • No ISO standards body; is not an explicit goal

Rust Example Code (Atomics)

use std::{any::Any, sync::atomic::{AtomicU64, Ordering}, thread};

type Result<T, E = Box<dyn Any + Send + 'static>> = core::result::Result<T, E>;

const THREAD_COUNT: usize = 100;
const INCREMENTS_PER_THREAD: usize = 10_000;

static COUNT: AtomicU64 = AtomicU64::new(0);

fn main() -> Result<()> {
    let mut join_handles = Vec::with_capacity(THREAD_COUNT);
    // Spawn all the threads
    for _ in 0..THREAD_COUNT {
        let join_handle = thread::spawn(|| {
            for _ in 0..INCREMENTS_PER_THREAD {
                // Read/Modify/Write is atomic (indivisible) and cannot race. Look Ma, no locks!
                COUNT.fetch_add(1, Ordering::SeqCst); // <-- SeqCst is conservative but never wrong
            }
        });

        // Add the newly created thread's handle to the list of already-created handles
        join_handles.push(join_handle);
    }

    // Wait for all threads to complete
    join_handles.into_iter().try_for_each(|jh| jh.join())?;

    // Print the total count.
    println!("Total count is {}", COUNT.load(Ordering::SeqCst));
    
    Ok(())
}
❯ cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/inc_locked`
Total count is 1000000

Process finished with exit code 0

Learning Resources

Coming from:

    * C?  Rust for C Programmers

    * C or C++?  Programming Rust,  Rust for Rustaceans

    * Above or Other Languages?  The Book

 

Looking for:

Memory Safety Features

Memory Management

* RAII (i.e. scope-based), Manual

* Compiler-enforced without runtime via borrow-checker

* Ref-counted memory resources also available (opt-in)

 

Lifetime Management

* Manual

* Common cases can be elided

* Can be complex

* Compiler-enforced without runtime via borrow-checker

Memory Safety Features

Bounds-Checking

* Yes, by default (impacts performance)

* Can be manually overridden (`unsafe`)

* Compiler often automatically elide bounds checking esp. when using functional paradigms

 

Safe Arithmetic

Integer Arithmetic

  • Defaults to C model: panic on debug, wrap (silently) in release; no UB!
  • supports safe integer arithmetic (`checked`, `wrapping`, `overflowing`, `saturating`)

Floating Point: IEEE-754-2008

 

Memory Safety Features

Pointers and References

* Yes, all Rust's safe pointers are... safe (`Arc`, `Box`, `RefCell`, et. al.)

* References (`&`, `&mut`) cannot be null and are always initialized (language invariant)

* Additional `unsafe` pointers are available (`UnsafeCell`, `*const`, `*mut`, et. al.)

* No `unsafe` nullable reference.

 

Forced Initialization

* Safe (default) Rust ensures all memory, types, references and safe pointers are initialized

* `unsafe` resources may require manual initialization

* Pointer arithmetic is supported  (unsafe, via `.add`, `.offset`, et. al.)

Memory Safety Features

Managed Ownership (Borrow-Checker)

* Compile-time--the benefits of GC/RC without any runtime overhead

* Via strict alias tracking and static analysis

* No additional code at runtime

* Aliasing guarantees provide additional compiler optimizations not possible otherwise

 

Thread Safety Features

Sync Primitives

* `Mutex`, `RwLock`, `Condvar`, guaranteed one-time initialization, Atomics, Memory Barriers (C++11 Model)

 

Reentrancy Safety

* Not by default; non-rentrancy-safe functions are safe from data races but may deadlock or panic (orderly termination of app).

* Careful design (manual) can yield reentrancy safe functions.

Thread Safety Features

Immutability

* Rust bindings (variables) are immutable by default.

* Immutability cannot be cast away.

 

Communication Primitives

* MPSC (Multiple-Producer, Single Consumer) channel, bounded and unbounded

* Other variants available as 3rd party libraries

* Streams, Websockets
* Unix pipes are not directly supported in `std`.

Performance

Determinism @ Runtime:

* Rust is suitable for hard realtime development, with careful use.

* Some types and functions are not suitable for hard-realtime use (e.g. `Vec`).

 

Bare Metal Programming

* Rust is suitable for bare-metal programming

* Innovative representation of hardware using typestate

* Innovative representation of hardware using `async`

Development Ecosystem

Available Toolchains

* `rustc` + LLVM

* Ferrocene (safety-qualified compiler)

* Cranelift

* `gccrs`, `rustc_codegen_gcc` (under development)

* `mrustc`

 

Library Support

* Good

* Some areas are thinner (ML/AI, UI, scientific, GPU), but options usually exist.

Development Ecosystem

Package Managers

* `cargo` is effectively the universal standard in Rust

 

IDE Editor Support

* `rust-analyzer` is a Rust Language Server Protocol (LSP) server implementation designed for use in most editors--`vim`, `emacs`, VSCode, Helix, `zed`, Sublime Text...

* Rust Rover or IntelliJ Rust for JetBrains IDE's

 

Community Size

* Medium to large and fast-growing

Other Considerations

Easy or Hard?

* Hard; Rust is not a small language and has some advance concepts.

 

Easy to Find Developers?

* In recent years, it has become reasonably easy to find Rust developers.

Other Considerations

Suitable for Use in Regulated Environments?

Yes, some:

  • ISO 26262 & ASIL-D (automotive)
  • IEC 61508 (SIL 4) (industrial manufacturing)
  • IEC 62304 (Class C) (medical development)
  • more in progress

 

Suitable for Use in Embedded Environments?

* Yes.  Jobs appearing in everything from automotive to NewSpace; clean energy to medical devices.

Other Considerations

Job Availability By Career Level

* Junior: scarce

* Mid-level: moderately scarce

* Senior: Moderate

* Staff/Principal: Moderate

Rust Example Code (Mutex Lock)

use std::{any::Any, thread, thread::JoinHandle};

use parking_lot::Mutex;

type Result<T, E = Box<dyn Any + Send + 'static>> = core::result::Result<T, E>;
const THREAD_COUNT: usize = 100;
const INCREMENTS_PER_THREAD: usize = 10_000;

static COUNT: Mutex<u64> = Mutex::new(0); // <-- New!

fn main() -> Result<()> {
    let mut join_handles = Vec::with_capacity(THREAD_COUNT);
    // Spawn all the threads
    for _ in 0..THREAD_COUNT {
        let join_handle = thread::spawn(|| {
            for _ in 0..INCREMENTS_PER_THREAD {
                let mut count_guard = COUNT.lock(); // <-- returns resource *guard*, not resource!
                *count_guard += 1; // <-- dereference guard to access `COUNT`. And no more `unsafe`!
            } // <-- guard drops automatically (unlocks), making lock available to other threads
        });
        // Add the newly created thread's handle to the list of already-created handles
        join_handles.push(join_handle);
    }
    // Wait for all threads to complete
    join_handles.into_iter().try_for_each(JoinHandle::join)?;

    // Print the total count.
    println!("Total count is {}", *(COUNT.lock())); //<-- Get lock, deref guard, get value, release
    Ok(())
}
❯ cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/inc_locked`
Total count is 1000000

Process finished with exit code 0

Rust Example

Code (Racy☠️)

use std::{any::Any, thread};

type Result<T, E = Box<dyn Any + Send + 'static>> = core::result::Result<T, E>;

const N_THREADS: usize = 100;
const INCS_PER_THREAD: usize = 10_000;

static mut COUNT: u64 = 0;

fn main() -> Result<()> {
    let mut join_handles = Vec::with_capacity(N_THREADS);
    // Spawn all the threads
    for _ in 0..N_THREADS {
        let join_handle = thread::spawn(|| {
            for _ in 0..INCS_PER_THREAD {
				COUNT += 1;
            }
        });

        // Add newly created thread's handle to list of already-created handles
        join_handles.push(join_handle);
    }

    // Wait for all threads to complete
    join_handles.into_iter().try_for_each(|jh| jh.join())?;

    // Print the total count.  It will be 1_000_000, right? Right?? ;)
    println!("Total count is {}", unsafe { COUNT });

    Ok(())
}
error[E0133]: use of mutable static is unsafe and requires unsafe block
  --> src/main.rs:16:9
   |
16 |         COUNT += 1;
   |         ^^^^^ use of mutable static
   |
   = note: mutable statics can be mutated by multiple threads: aliasing violations or
           data races will cause undefined behavior

Rust Example

Code (Racy☠️)

use std::{any::Any, thread};

type Result<T, E = Box<dyn Any + Send + 'static>> = core::result::Result<T, E>;

const THREAD_COUNT: usize = 100;
const INCREMENTS_PER_THREAD: usize = 10_000;

static mut COUNT: u64 = 0;

fn main() -> Result<()> {
    let mut join_handles = Vec::with_capacity(THREAD_COUNT);
    // Spawn all the threads
    for _ in 0..THREAD_COUNT {
        let join_handle = thread::spawn(|| {
            for _ in 0..INCREMENTS_PER_THREAD {
				unsafe { COUNT += 1; }
            }
        });

        // Add newly created thread's handle to list of already-created handles
        join_handles.push(join_handle);
    }

    // Wait for all threads to complete
    join_handles.into_iter().try_for_each(|jh| jh.join())?;

    // Print the total count.  It will be 1_000_000, right? Right?? ;)
    println!("Total count is {}", unsafe { COUNT });

    Ok(())
}
❯ cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.10s
     Running `target/debug/inc_racy`
Total count is 192008
❯ cargo run
Total count is 189345
❯ cargo run
Total count is 198313
❯ cargo run --release # <-- compile in release mode
    Finished `release` profile [optimized] target(s) in 0.00s
     Running `target/release/inc_racy`
Total count is 1000000 # <-- !!

Rust

Why Was Rust Created?
 

"A lot of obvious good ideas, known and loved in other languages, haven't made it into widely-used systems languages, or are deployed in languages that have very poor (unsafe, concurrency-hostile) memory models. There were a lot of good competitors in the late 70s and early 80s in that space, and... circumstances have changed: the internet is highly concurrent and highly security-conscious, so the design-tradeoffs that always favor C and C++ (for example) have been shifting."

- Graydon Hoare, 2012

Thank you.

SRUG 2025.07: Language Panel

By u007d

SRUG 2025.07: Language Panel

  • 103