Idioms and Patterns Story
Hello Data
Home
Repo
prev
next
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.