Learning Programming Concepts by Jumping in at the Deep End
There are many different ways to learn something; one that I enjoy from time to time is what I'd call the "jump in at the deep end": Look at the solution to a problem and study each of its details until you understand all the concepts.
This is in contrast to a tutorial-style learning where you learn one thing after another and gradually build more complex things. I like the "deep end" approach because it's a very personal learning style. It often gives me a way to discover interesting aspects of things myself, try to find out how parts work together, and play around with the material until I think I've got how it works. And while the road to understanding might be full of little frustrations and missing knowledge, I find it a very rewarding exercise. (Or maybe I'm just one of those people who like to geek out about neat concepts.)
Recently, I came across this task: Count the individual words in a given text. The solution I found seemed like a good "deep end" problem to me. It's short and yet full of different concepts.
Here's what I'd write (in Rust):
It's just 8 lines! (You can play with the code here.)
And here are the concepts you should study to fully understand what's going on (in no particular order; I tried to add a lot of links):
- Functions: fn count_words
- Modules and imports: use std::…
- Strings and characters: &str and ' ' are guaranteed to be UTF-8
- Slices: views into/references to memory and, in Rust, their lifetimes: the &strs in the hash map are slices of the input text
- Iterators: split returns a type that implements Iterator
- fold (a.k.a. reduce): A core part of functional programming (more information)
- Iterator: a trait
- Map data type: HashMap
- Hashing
- Generic data types: Split<'a, P>, HashMap<K, V>
- Rust's entry API: A view into a map with the ability to transform/add items
- closures: |x, y| { … }
- Implicit return, last expression in a block gets returned: { …; map } returns map
- Mutable vs. immutable variable bindings: mut map
- References, pointers, dereferencing: thingy and &thingy
- Integer sizes: usize
- Built-in operators: +=
Note that most of these concepts are not special to Rust. I've just written this in Rust because it's the language I currently use the most in my free time, and also because it's a language that exposes you to a lot of interesting concepts.
Just for comparison, here's the same in JavaScript (play with it on JSBin):
Discussion in the ATmosphere