Idioms and Patterns Story
Hello Data
Home  Repo
Top, Bottom

Hello Data

Demonstration compares C#, C++, and Rust "Data Operations" programs


Each item in the IdiomsAndPatterns repository focues on a simple program construct built in each of the three languages: C++ 20, Rust 1.49, and C# 9.0. This may help you use what you know of C++ or C# (or Java) to learn Rust more easily. This page demonstrates bind, copy, and move operations. Find instructions for downloading build chains for each of these languages in Tooling.
C++ hide /* DataOps.cpp - demo data operations */ #include <iostream> #include <vector> #include <string> template <typename Coll> void show( const Coll& c, const std::string& msg = "" ) { std::cout << "\n "; if(msg.length() > 0) { std::cout << msg << " "; } using typename ValType = Coll::value_type; for(ValType item : c) { std::cout << item << " "; } } int main() { std::cout << "\n -- demo data operations --\n"; /* Primitive data types: int, double, ... occupy contiguous regions of memory, so copies simply copy memory. */ std::cout << "\n -- integer ops --"; int x = 42; auto y = x - 2; // copy construction std::cout << "\n x = " << x << ", y = " << y; x = y; // copy assign std::cout << "\n after copy assign: x = y"; std::cout << "\n x = " << x << ", y = " << y << "\n"; /* Most non-primitive types: Vec<T>, String, ... occupy memory on stack and heap, so they do not satisfy copy trait, so need copy ctor and copy assign operations. These often, but not always, can be correctly built by compiler, as needed. */ std::cout << "\n -- Vec ops --"; std::vector<int> v { 1,2,4 }; show(v, "v = "); auto w = v; // copy assign - a clone std::cout << "\n after copy construction: let w = v:"; show(v, "v = "); show(w, "w = "); std::cout << "\n set w[1] = -2"; w[1] = -2; show(v, "v = "); show(w, "w = "); std::cout << "\n\n That's all Folks!!\n\n"; } C++ build and execute -- demonstrating data operations -- -- integer ops -- x = 42, y = 40 after copy assign: x = y x = 40, y = 40 -- Vec ops -- v = 1 2 4 after copy construction: let w = v: v = 1 2 4 w = 1 2 4 set w[1] = -2 v = 1 2 4 w = 1 -2 4 That's all Folks!! Rust unhide /* DataOps::main.rs - demo Rust Data Ops */ fn main() { print!( "\n -- demo data operations --\n" ); /* Primitive data types: i32, f64, ... occupy contiguous regions of memory, so they satisfy the copy trait */ print!("\n -- integer ops --"); let mut x :i32 = 42; let y = x - 2; // copy construction print!("\n x = {}, y = {}", x, y); x = y; // copy assign print!("\n after copy assign: x = y"); print!("\n x = {}, y = {}\n", x, y); /* Most non-primitive types: Vec<T>, String, ... occupy memory on stack and heap, so they do not satisfy the copy trait */ print!("\n -- Vec ops --"); let v:Vec<i32> = vec![1,2,4]; print!("\n v = {:?}", v); let w = v; // move assign print!( "\n after move construction: let w = v:" ); print!("\n w = {:?}", w); print!( "\n now v is invalid (been moved)\n" ); let x = w.clone(); print!( "\n after clone oper: let x = w.clone():" ); print!("\n w = {:?}", w); print!("\n x = {:?}", x); println!("\n\n That's all Folks!!\n\n"); } Rust build and execute C:\...\DataOperations\RustData> cargo run -q -- demonstrating data operations -- -- integer ops -- x = 42, y = 40 after copy assign: x = y x = 40, y = 40 -- Vec ops -- v = [1, 2, 4] after move construction: let w = v: w = [1, 2, 4] now v is invalid (been moved) after clone operation: let x = w.clone(): w = [1, 2, 4] x = [1, 2, 4] That's all Folks!! C# hide /* Program.cs -- Demo Data Operations */ using System; using System.Collections.Generic; namespace CSharpData { class Program { static void show<T>( IEnumerable<T> c, String msg = "" ) { Console.Write("\n "); if(msg.Length > 0) Console.Write("{0} ", msg); foreach(T item in c) { Console.Write("{0} ", item); } } static void Main(string[] args) { Console.Write( "\n -- C# data operations --\n" ); /* Primitive types in C# are copy types, just like C++ and Rust. */ Console.Write("\n -- integer ops --"); int x = 42; int y = x - 2; Console.Write( "\n x = {0}, y = {1}", x, y ); x = y; Console.Write("\n after copy assign:"); Console.Write( "\n x = {0}, y = {1}\n", x, y ); /* Non-primitive types are handle copy types not instance copy. Instances reside in the managed heap, and are accessed only through handles, like v and w, below. Copy construction creates a new handle to the original instance. Copy assignment does the same thing. */ Console.Write("\n -- List<int> ops --"); List<int> v = new List<int>(); int[] rng = { 1, 2, 3 }; v.AddRange(rng); show(v, "v = "); var w = v; Console.Write( "\n after copy construct var w = v:" ); show(v, "v = "); show(w, "w = "); w[1] = -2; Console.Write( "\n after setting w[1] = -2:" ); show(v, "v = "); show(w, "w = "); /* Note that both v and w show change, because they are both handles to same managed heap instance. */ Console.WriteLine( "\n\n That's all Folks!\n\n" ); } } } C# build and execute C:\...\DataOperations\CSharpData> dotnet run -- C# data operations -- -- integer ops -- x = 42, y = 40 after copy assign: x = 40, y = 40 -- List ops -- v = 1 2 3 after copy construct var w = v: v = 1 2 3 w = 1 2 3 after setting w[1] = -2: v = 1 -2 3 w = 1 -2 3 That's all Folks!

4. Epilogue

The following pages provide sequences of code examples for idioms and principles in each of the three languages cited here, e.g. C#, C++, and Rust. Object model differences will often be pointed out in comments within the code blocks.