Code Story

Chapter #1 – Data

primitive types, composite types, strings, type aliases

1.0  Prologue

Every value in a program has a type. The type tells the compiler how many bytes to allocate, what operations are valid, and how to interpret the stored bit pattern. Languages differ in which types they provide natively, how they name them, and how strictly they enforce type boundaries at compile time versus runtime.

1.1  Primitive Types

Primitive types map directly to hardware operations. They are value types: copying one produces an independent duplicate with no shared state. Integer types vary by signedness and width:
Rust C++ C# Python
i8, i16, i32, i64, i128, isize int8_t … int64_t, ptrdiff_t sbyte, short, int, long int (arbitrary precision)
u8, u16, u32, u64, u128, usize uint8_t … uint64_t, size_t byte, ushort, uint, ulong -
Floating-point types follow IEEE 754:
Rust C++ C# Python
f32, f64 float, double, long double float (32-bit), double (64-bit) float (always 64-bit)
Boolean: bool in all four languages; values are true and false. C++ historically treated any non-zero integer as truthy, but modern C++ and all other listed languages require an explicit bool in conditional expressions. Character: Rust char is a Unicode scalar value (4 bytes). C++ char is implementation-defined (typically 1 byte, ASCII or UTF-8 byte). C# char is a UTF-16 code unit (2 bytes). Python has no separate char type - a single-character string serves the same role.

1.2  Composite Types

Composite types aggregate multiple values into one. Unless heap-allocated, they are also value types and are copied when assigned. Arrays hold a fixed number of elements of the same type in contiguous memory. The size is part of the type in Rust and C++: // Rust let a: [i32; 4] = [1, 2, 3, 4]; // C++ std::array<int, 4> a = {1, 2, 3, 4}; // C# int[] a = {1, 2, 3, 4}; // heap-allocated, fixed size at creation // Python a = [1, 2, 3, 4] # list, mutable and dynamically sized Tuples hold a fixed number of elements of possibly different types. Access is by index (Rust: t.0, C++: std::get<0>(t)): // Rust let t: (i32, f64, bool) = (1, 2.5, true); let x = t.0; // C++ auto t = std::make_tuple(1, 2.5, true); int x = std::get<0>(t); // C# (int, double, bool) t = (1, 2.5, true); int x = t.Item1; // Python t = (1, 2.5, True) x = t[0] Structs group named fields and are the primary vehicle for modeling domain objects. In Rust and C++ they are value types on the stack by default; in C#, struct is a value type while class is a reference type; in Python all objects are reference types. Enums (tagged unions) represent a value that is exactly one of several named variants. Rust enums carry per-variant data, making them full algebraic data types. C++ enums are plain integer aliases. C# enums are integral constants. Python enum.Enum provides named constants but not per-variant data.

1.3  String Types

Strings are sequences of character data. Languages differ sharply in ownership, encoding, and mutability. Rust distinguishes String (owned, heap-allocated, valid UTF-8) from &str (borrowed slice of UTF-8 bytes). Indexing by integer is not allowed because a UTF-8 scalar is 1–4 bytes. C++ std::string owns heap memory (raw bytes, UTF-8 by convention). std::string_view is a non-owning reference analogous to Rust’s &str; it does not own or null-terminate. C# string is an immutable reference type on the heap, encoded as UTF-16. System.Span<char> provides a low-allocation slice for processing. Python str is an immutable sequence of Unicode code points. Indexing yields a code point, not a byte. bytes holds raw binary data and does not interpret encoding.

1.4  Type Aliases

A type alias gives an existing type a new name. It aids readability and centralizes the definition when the underlying type might change. Aliases do not create new types - the compiler treats the alias and the original as identical. // Rust (transparent alias) type Meters = f64; // Rust (newtype - distinct type, zero runtime overhead) struct Meters(f64); // C++ using Meters = double; typedef double Meters; // older syntax, identical semantics // C# (C# 12+) using Meters = double; // Python Meters = float # convention only; runtime treats it as float A newtype (Rust’s single-field tuple struct) creates a type the compiler treats as distinct from the wrapped type. This prevents accidentally mixing logically different quantities that share the same representation, such as meters and seconds both stored as f64.

1.5  Epilogue

Choosing the right data type is the first design decision in every function. Correct types make invalid states unrepresentable and give the optimizer reliable information. The next chapter covers how values are bound to names and how binding rules govern mutability and scope.

1.6  References

Rust Data Types - The Book
C++ Fundamental Types - cppreference
C# Built-in Types - Microsoft
Python Built-in Types