24 Feb 25
Fascination Street #7
Writing for the week of Feb 24, 2025
This week has been a heads down, work on a bunch of Rust code, week. I updated some of my tooling and that felt good. Maybe I’ll write about it soon. Outside of work, I’m continuing to write the book mentioned in the footer of this newsletter.
If you’re a Rubyist wanting to learn Rust, here is an unedited sneak peek on the chapter about Vectors:
Vectors
In the last chapter, we made a comparison between Rust Structs and Ruby Classes. Are they identical other than in name? No. But they do represent the same thing from a basic structure of code paradigm.
In this chapter, we are going to do a similar comparison between Rust’s Vectors and Ruby’s Arrays.
Vectors are integral to Rust. Strings are stored as Vectors. Vectors aren’t mutable by default. That’s a fun twist compared to Ruby’s Arrays.
Vectors, like Arrays, are collections. They hold elements. Typically of the same type. Though, sometimes we have to declare the type as we’ll see.
In our Ruby project, we have already declared a few arrays. However, let’s get explicit. In the Struct chapter, we set up a User class with kinds of users. Previously, our array contained Classes as elements. Let’s make this more simple by using Strings as the elements.
class User attr_accessor :kinds def initialize() @kinds = ['singer', 'guitarist'] end end puts User.new().kinds #=> singer guitarist
The equivalent of that in Rust would be something like the following.
struct User<'a> { kinds: Vec<&'a str> } let user = User { kinds: vec!["singer", "guitaist"]}; println!("{:#?}", user.kinds); // => ['singer', 'guitarist']
Ignore the <‘a>
for now on the Struct definition. That is related to lifetimes, which I’ll cover in a later chapter. For now, the important thing is the definition of a Vector.
In Ruby, we can declare some properties of our Array when we create it. For example, the length (of 3) with Array.new(3)
. We can also set the default value for elements with Array.new(3, 'foo')
.
With Rust, we can declare the type of elements the Vector will hold. For example, with String elements: Vec<String>
. Or with Integer values: Vec<u8>
.
// string elements let strings: Vec<String> = vec![String::from("foo"), String::from("bar")]; // integer elements let integers: Vec<u8> = vec![1,2];
But as mentioned previously, Rust Vectors are not mutable by default like Arrays are in Ruby. If we try to add an element to the integer example above, we’ll receive an error.
let integers: Vec<u8> = vec![1,2]; integers.push(3); println!("{:#?}", integers);
On the first line, we declare our variable with a type of Vector1,2
. On the next line, we try to add the value 3
to the Vector using the push
method. The result is an error:
error[E0596]: cannot borrow `integers` as mutable, as it is not declared as mutable --> src/main.rs:183:5 | 183 | integers.push(3); | ^^^^^^^^ cannot borrow as mutable | help: consider changing this to be mutable | 182 | let mut integers: Vec<u8> = vec![1,2]; | +++
The error explains pretty clearly what is happening. It also gives a solution. We can use the mut
keyword to make our Vector mutable. Once we add the keyword, we can add the value of 3
to our Vector. With the exception of the mut
keyword, so far the functionality is pretty close to Ruby’s Array.
In Ruby, we can use Arrays to store elements of multiple types. For example, we can store both Strings and Integers.
a = Array.new a << 1 a << 'foo' puts a.join(',') # => 1,foo
This can be done in Rust, but it requires declaring an Enum with the known types.
#[derive(Debug)] enum MultiType { Integer(u8), Text(String), } let multi: Vec<MultiType> = vec![ MultiType::Integer(1), MultiType::Text(String::from("foo")) ]; println!("{:#?}", multi);
That’s different and takes some time to wrap your head around when coming from Ruby. The other major thing that feels different about Rust Vectors compared to Ruby Arrays is how you enumerate over them.
In Ruby, Arrays are enumerable. We can do a loop over the values in multiple ways.
my_array = [1, 2, 3] my_array.each do |num| puts num end
In Rust, we have to make our Vector iterative which is similar in concept to an object being enumerable in Ruby.
let my_vector = vec![1,2,3]; my_vector.iter().for_each(|num| println!("{}", num));
But why do we have to make the Vector iterative first? Rust Vectors iterators are lazy. They don’t evaluate the element value until required. This allows us to combine multiple transformations over a single iteration of the data.
On the flipside of an iterator is a consumer. In the above example, we turn the Vector into an iterator and then chain on a consumer with the for_each
method. Similar consumers include map
, filter
, and fold
.
Before we get too deep into iterators and consumers, let’s look at more simple use cases for Vectors.
In Ruby, it’s easy to get to an element of a zero-index array using the bracket syntax.
my_array = [1, 2, 3] puts my_array[0] # => 1
In Rust, we can do something similar.
let my_vector = vec![1,2,3]; println!("{}", my_vector[0]);
In Ruby, we can iterate over an Array and transform the values easily. We’ll use map!
to transform the original array.
my_array = [1, 2, 3] my_array.map! { |element| element + 1 } puts my_array
In Rust, we have to consider mutability. In that case, we declare our Vector as mutable and use a different iterator called iter_mut
.
let mut my_vector = vec![1,2,3]; for elem in my_vector.iter_mut() { *elem += 1; } println!("{:#?}", my_vector);
–
That’s it for this week. I’m continuing to grow the topics I want to cover in the book. I added a number of chapters this week. At some point I need to ship it. Andy Warhol’s words about artists never wanting to be done is ringing in my ears. He advised that you may just have to force yourself to call your art done. You know that question where someone asks who you would like to have dinner with, both living and dead? Andy Warhol would be on the list for me. Along with my great grandmother and Robert Smith. I laugh picturing it.
▧ ▧ ▧
Links
- https://andrew-jones.medium.com/integration-without-coupling-with-data-contracts-4ede508eb9e6 - I really need to read Andrew’s book because I see these posts and nod along. Been there, done that. So true with this post.
- https://web.archive.org/web/20250210033440/https://andysblog.uk/why-blog-if-nobody-reads-it/ - I think I stole this one from Thorsten but I love it. I’ve never had a ton of followers. I don’t write things on the internet because I aspire to have a ton of followers. I write for my own clarity. Writing forces me to sit down and make sure I understand a topic and structure my thoughts about it. Bravo to the original poster.
- https://waitbutwhy.com/2014/05/life-weeks.html - I may have stole this from Thorsten as well, but the idea of having a timeline of the weeks in your life is fascinating. Imagine going through the exercise thinking of what major thing happened to you. Most of us would have to dig through old emails or photos. Our kids shouldn’t have to do that. I kinda want to build an app now for parents to record their kids weekly timeline. Stay tuned….
▧ ▧ ▧
Music
- old Wire - relistening to Pink Flag some this week, art school post-punk from the 70s
- old Pylon - listening to the Box compilation, admittedly I don’t know a lot about Pylon yet
- new Haunt Me - new album Watch You Bleed, love Haunt Me, this album feels like an evolution
▧ ▧ ▧
A couple of promotions each week. First, use my invite link to try Warp as your terminal. It’s fast and has some great features. I’m not affiliated with them at all, just really like it. Also, check out my project–Schemabook, especially if you work in an organization that wants to get organized around defining data through contracts and collaboration. Lastly, I’m writing a book about learning Rust if you are familiar with Ruby. Stay tuned. As always, you can connect with me more at https://mikekrisher.com.