Recall Type Systems: Rules linking type to constructs
Type Systems give meaning to constructs (bits)
Tells us two things:
Will accept "good" programs
// Java
String x = "4" + 2.0;
// C
int x = *"4" + 2.0;
(* OCaml *)
let x = 4 + 20
Will reject "bad" programs
// Java
boolean x = "4" < 2.0;
// C
int x = "4" + 2.0;
(* OCaml *)
let x = 4 + 2.0
Will accept "good" programs
Will reject "bad" programs
How: Project 5 - Check types of AST
How: Project 5 - Check types of AST
Recall Ontological Problem
Exapnd Identity \(\Rightarrow\) Expand capabilities
Exapnd Identity \(\Rightarrow\) Expand capabilities
Rust: Check not just types, but more
C is fast, but memory is unsafe
Java,OCaml,Python: slower but memory is safe
Why slow: Recall Garbage Collection
Why slow: Recall Garbage Collection
In Particular: Heap
Stack is automatic:
Solve this problem: no GC needed
Statically figure out when something should be dropped (freed)
Ownership Rules
(Important for heap values)
(Important for heap values)
Strings: values stored on the heap
let x = String::from("Hello"); //not a literal
let mut y = String::from("Hello"); //different from x
y.push_str(" world"); //modify y
Each value in Rust has an owner
let x = String::from("Hello"); // x owns "Hello"
let mut y = String::from("Hello"); // y has it's own version
y.push_str(" world");
println!("{x}"); // "Hello"
println!("{y}"); // "Hello World"
There can only be one owner at a time
let x = String::from("Hello"); // x owns "Hello"
let y = x; // ownership is MOVED from x to y
println!("{x}"); // ERROR
x becomes invalid
When the owner goes out of scope, the value will be dropped
{
let x = String::from("Hello"); // x owns "Hello"
println!("{}",x);
} // x is DROPPED
1 owner \(\Rightarrow\) no double free
1 owner \(\Rightarrow\) no double free
There can only be one owner at a time
{
let x = String::from("Hello"); // x owns
let y = x; // now y, x becomes invalid
} // drop y
Strings will shallow copy by default
Need to track values through program flow
fn main() {
let s = String::from("hello");
takes_ownership(s);
println!("{s}"); //ERROR
}
fn takes_ownership(some_string: String) {
println!("{}", some_string);
}
Line 9: "hello" is dropped
Need to track values through program flow
fn main() {
let s = String::from("hello");
let y = takes_returns_ownership(s);
println!("{y}");
}
fn takes_returns_ownership(some_string: String)->String {
println!("{}", some_string);
some_string
}
Line 5: "hello" is dropped
Need to track values through program flow
Issue with transfer
fn main() {
let s = String::from("hello");
let l = takes_ownership(s);
println!("{s} is {l} long"); //ERROR
}
fn takes_ownership(some_string: String)-> usize {
some_string.len()
}
Line 9: "hello" is dropped
Need to track values through program flow
fn main() {
let s = String::from("hello");
let (y,l) = annoying(s);
println!("{y} is {l} long");
}
fn annoying(some_string: String)->(String,usize) {
let l = some_string.len();
(some_string,l)
}
Fix with references
Allows access to values without moving ownership
let x = String::from("Hello");
let y = &x; // x still owns "hello"
fn main() {
let s = String::from("hello");
let l = annoying(&s);
println!("{s} is {l} long");
}
fn annoying(some_string: &String)->(usize) {
some_string.len()
}
Allows access to values without moving ownership
Ownership cannot move while references exist
fn main() {
let x = String::from("hello");
let y = &x; // borrow occurs here
let z = x; // ERROR
println!("{y}");
}
Allows access to values without moving ownership
Ownership cannot move while references exist
fn main() {
let s = String::from("hello");
let (y,l) = annoying(s);
println!("{y} is {l} long");
}
fn annoying(some_string: String)->(String,usize) {
//let l = some_string.len();
//(some_string,l)
(some_string,some_string.len()) // ERROR
}
Struct's have a ref to self
Can make mutable references
let mut x = String::from("Hello");
let y = &mut x;
y.push_str(" world!");
println!("{x}"); // Hello world
Important: y is not mutable
Can make mutable references
Important: y is not mutable
let mut x = String::from("Hello");
let y = &mut x;
y.push_str(" world!");
println!("{x}"); // Hello world
y points to mutable data
Can make mutable references
Mutable Variable \(\not\Rightarrow\) Mutable refernce
let mut x = String::from("Hello");
let mut y = String::from("World");
let a = &x; // immutable a borrows x immutably
let b = &mut x; // immutable b borrow x mutably
let mut c = &x; // mutable c borrows x immutably
let mut d = &mut x; // mutable d borrows x mutably
let mut x = String::from("Hello");
let mut y = String::from("World");
let a = &x; // immutable a borrows x immutably
let b = &mut x; // immutable b borrow x mutably
b.push_str("!"); // x = Hello!
b = &mut y; // ERROR
let mut c = &x; // mutable c borrows x immutably
c = &y; // c now points to World
let mut d = &mut x; // mutable d borrows x mutably
d.push_str("!"); // x is now Hello!!
d = &mut y; // d now points to World
let mut x = String::from("Hello");
let mut y = String::from("World");
mut is now part of type
let mut a = &mut x;
a = &y; // ERROR - mismatched types: &mut string != &String
Rust: no data races \(\Rightarrow\) safety
Mutable references can cause data race
In other languages
Mutable references can cause data race
In other languages
Rust Type System prevents this with 2 rules:
ie. no dangling pointers!
fn dangle() -> &String {
let s = String::from("hello");
&s
}
Rust will not compile this
Lifetimes: future lecture
let x = String::from("Hello");
let y = &x;
let z = &x;
let mut x = String::from("Hello"); // x is mut ref to Hello
let y = &mut x; // y is mut ref to Hello
println!("{x},{y}"); // ERROR
let mut x = String::from("Hello"); // x is mut ref to Hello
let y = &mut x; // y is mut ref to Hello
println!("{x},{y}"); // ERROR
let mut x = String::from("Hello"); // x is mut ref to Hello
{
let y = &mut x; // y is mut ref to Hello
println!("{y}");
} // y mut ref goes away
println!("{x}"); // now we can use x
Update: scope of ref changed Fall 23 (Rust 1.62-2022)
Scope of ref is from when made to last used
let mut x = String::from("Hello");
let y = &mut x;
println!("{y}");
println!("{x}"); // OKAY
let mut x = String::from("Hello");
let y = &mut x;
println!("{x}");
println!("{y}"); // NOT OKAY