Twitter: @GolDDranks ▸ From: Finland ▸ Does: A software engineer in a Japanese company ▸ Also does: Rust related stuff and programming for fun! ▸ A Rustacean for a little over 5 years – before 1.0!
DEFINITIONS ▸ the narrow one: the story of λ ▸ 1. functions are values too! ▸ 2. side-effects? let’s not. ▸ the wider one: the story of types, immutability, messages, linearity, effects.. ▸ in other words: here's the premise... ▸ but what should we build on top of it?
CALCULUS ▸ the mathematical "bias": there are things we never dispute ▸ evaluating an expression doesn't change anything ▸ referential transparency ▸ once defined object doesn't mutate ▸ immutability ▸ cloning information doesn't cost anything ▸ so obvious that only its converse has got a name: ▸ linearity
CALCULUS ▸ the mathematical "bias": there are things we never dispute ▸ anything is a first-class object ▸ i.e. we don't have to care about implementation details for practicality or efficiency ▸ including: functions, sets (= types), sets of functions (= lambdas/closures/function pointers), functions with codomain in sets (= type constructors)... but also including relations, proofs, signatures, modules (in all of its meanings), algebras...
OR EVEN DECENT? ▸ iron-clad properties: ▸ no side-effects ▸ subdelegation with trust ▸ functions calling functions ▸ knowing that things you call can't hurt you ▸ functions as values ▸ expressivity: code is data — data is code
OR EVEN DECENT? ▸ iron-clad properties: ▸ lazyness ▸ expressivity! write what you think, not what is efficient ▸ types ▸ the compiler is going to check your bugs for you ▸ and in case you didn't have any types, infer them
begat?: erlang ▸ begat: elixir (← we are finally talking about modern things, huh?) ▸ these languages are about objects?! ▸ but they are principled! ▸ maybe we are on to something?!
CHAT ▸ a minimal language of a bunch of objects talking to each other ▸ no object can violate the state of another object ▸ encapsulation ▸ message passing
DID ALL OF THIS? ▸ embracing the core tenets: ▸ functions are values ▸ immutability ▸ still, the world is made of mutable state ▸ communicating objects ▸ control by message passing
IS FUNCTIONAL PROGRAMMING? ▸ the simpl(istic) answer: a haskell (← not to be taken lightly!) ▸ the wider view: ▸ anything that is inspired/motivated by the the core ideas ▸ including things that aren't strictly limited to programming with functions ▸ "functional" is programming with smart, good ideas
IS FUNCTIONAL PROGRAMMING? ▸ furthermore, functional programming is not a property of a a language ▸ even though some languages have affinity to FP ▸ it's a style of writing programs
IS IT FOR? ▸ providing a platform for application programming ▸ required: low level control ▸ providing shared functionality ▸ libraries ▸ sometimes required: being agnostic of a platform
▸ many of our assumptions don't survive a contact with the real world ▸ not all information is easily clonable ▸ resources: files, network connections, hardware ▸ the real world is mutable ▸ we can't afford sacrificing performance and control for nicer abstractions
▸ → functional programming is awesome but it doesn't match how the world works too well ▸ in systems programming, you must care about how to world works!
▸ unashamedly systems-y programming language ▸ more C++ than C++, in where C++ means the good parts of C++ ▸ uncompromisingly memory safe ▸ the division between "safe" and "unsafe"parts actually means something ▸ uncannily functional → we want to delve into this!
UNDER YOUR FEET ▸ the compiler is going to be angry at you if you try! ▸ let state = State!::new(); state.method(); ▸ we can be sure that state is still the same after the method call! ▸ there are exceptions though...
are first-class values ▸ let people = "Wizard Whitebeard, Woof, Odlaw, Wenda, and Wally"; let initials = people.find( |c: char| c.is_uppercase()); ↑ anonymous function
▸ you can iterate over collections, map, flat_map, filter etc. ▸ let a = [0, 1, 2]; let mut iter = a.iter().filter(|&x| *x > 1); iter.next() ▸ produces Some(2)
PARAMETRIC POLYMORPHISM ▸ abstracting functionality that is common between types ▸ trait Eq { fn eq(&self, other: Self) !-> bool; } ▸ sadly, no higher kinded types supported at the moment...
& OWNERSHIP ▸ a value that can have only one owner ▸ you can track resources precisely ▸ you have the full control because only you have the access ▸ when you're done, you know when to destroy it
& OWNERSHIP ▸ fn read_book(book: Book) { println!("Reading {}", book); } let b = Book!::new(); read_book(b); ← Move the value inside the function read_book(b); ← COMPILER ERROR: CAN'T USE A MOVED VALUE!
& OWNERSHIP ▸ mutating stuff we own is OK. ▸ from FP perspective it's the same as consuming a value and creating a new one! ▸ fn read_book(mut book: Book) { book.write_notes(); ← mutation! println!("Reading {}", book); } let b = Book!::new(); read_book(b);
BORROWS ▸ Borrowing takes a reference to an object. The borrow automatically ends, and the original owner has it back. ▸ fn read_book(book: &Book) { println!("Reading {}", book); } let b = Book!::new(); read_book(&b); ← The function borrows the value
BORROWS ▸ there is two kinds of borrowing: ▸ shared: &book ▸ allows multiple simultaneous borrows ▸ doesn't normally allow mutating the borrowed thing ▸ unique: &mut book ▸ allows only one simultaneous borrow ▸ allows mutating the borrowed thing
BORROWS ▸ borrowing stuff as shared gives you the peace of mind ▸ i'm passing a reference to my book to this function, but it can't mutate or deallocate it ▸ let b = Book!::new(); let borrow_1 = &b; ← storing the reference in a variable let borrow_2 = &b; ← creating a second one is OK! compare_books(borrow_1, borrow_2);
BORROWS ▸ borrowing stuff as unique is powerful! ▸ the borrower can mutate the thing! ▸ but importantly, they can't deallocate it. ▸ unique means here that even the owner can't access it while it's borrowed! ▸ let mut b = Book!::new(); scribble_in_book(&mut b);
SECRET SAUCE ▸ MUTABILITY XOR SHARING ▸ ...is enough to preserve ▸ your code's safety ▸ your sanity ▸ functional programming that limits itself to immutable, shareable values is leaving the other option to the table!
additionally: affine typing gets a special mention ▸ stretching the metaphor: it's the most important spice in the sauce. ▸ affine means that the type system ensures that a value is used at most once. ▸ without the ability to ensure that, we couldn't control sharing
mutability makes rust suitable for system programming ▸ but the ability to restrict it makes Rust sane – in a way that resembles functional programming!
PROGRAMMING LANGUAGE? ▸ in a narrow sense, it isn't ▸ but i like to think it as a part of the bigger story of history of functional programming ▸ Rust takes inspiration from a huge number of great ideas from functional language ▸ i sincerelly hope it also is able to give something back
after referential transparency! ▸ const functions ▸ functions that are executable compile-time ▸ functions that only, and deterministically depend on the inputs
this referentially transparent? ▸ fn mutate_thing(&mut Thing) ▸ traditionally, no! ▸ but because of the sharing restriction, it can be regarded as that: ▸ state before call ≒ input ▸ state after call ≒ output
types: "generic associated types" ▸ needed mostly because there are some patterns around "streaming iterators" and "collections" that the type system is unable to represent ▸ however, brings some power of higher-kinded types to the language
polymorphic bounds based on the exact type (like C++ template specialization) ▸ this might be sad for some haskellers: ▸ partial loss of "parametricity": less "theorems for free" ▸ however, it's an excellent example of an balancing act between systems and functional programming